
using System;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.InteropServices;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.IO;

namespace FileDialog_GUI
{
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GUI-FileDialog 
    /// 
    /// written by Christ Kennedy 2019/12 - 2020/01
    /// Christ.Kennedy@mail.mcgill.ca
    /// 
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    #region FileDialog
    /// <summary>
    /// instantiates an OpenFileDialog that inherits FileDialog_GUI
    /// </summary>
    public class OpenFileDialog_GUI : FileDialog_GUI
    {
        public OpenFileDialog_GUI()
        {
            ConfirmText = "Open";
        }
    }

    /// <summary>
    /// instantiates a SaveFileDialog that inherits FileDialog_GUI
    /// </summary>
    public class SaveFileDialog_GUI : FileDialog_GUI
    {
        string strDefaultExt = "";
        public string DefaultExt
        {
            get { return strDefaultExt; }
            set { strDefaultExt = value; }
        }

        public SaveFileDialog_GUI()
        {
            ConfirmText = "Save";
        }

        override public string FileName
        {
            get
            {
                if (lstFiles.Count > 0)
                {
                    string strRetVal = lstFiles[0];
                    int intExtensionIndex = strRetVal.IndexOf('.');
                    if (intExtensionIndex < 0)
                        strRetVal += "." + DefaultExt;
                    return strRetVal;
                }
                else
                    return txtInput.Text;
            }
        }
    }

    /// <summary>
    /// instantiates a GUI-FileDialog that inherits a PerPixelAlpha form
    /// </summary>
    public partial class FileDialog_GUI : PerPixelForm._PerPixelAlphaForm
    {
        #region VariableDeclarations
        public static FileDialog_GUI instance = null;
        Size szMin = new Size(10, 10);
        /// <summary>
        /// contains the text typed in the UserInput_TextBox region
        /// </summary>
        public TextBox txtInput = new TextBox();
        TextBox txtLoseFocus = new TextBox();
        Semaphore semMouseMove = new Semaphore(1, 1);
        Semaphore semMouseDown = new Semaphore(1, 1);
        Semaphore semMouseDoubleClick = new Semaphore(1, 1);

        Point ptGrab = new Point();
        Point ptRelativeToScreen_Grab = new Point();
        Point ptMultiSelect_Grab = new Point();
        Point ptMultiSelect_Current = new Point();

        List<string> lstDirectories = new List<string>();
        classSweepAndPrune cSweepAndPrune = new classSweepAndPrune();
        enuState eState = enuState.UserInput;
        enuCursorState _eCursorState = enuCursorState.Off;
        ContextMenu cMnu = new ContextMenu();
        /// <summary>
        /// Binary Tree used to search Directory Tree Items by path
        /// </summary>
        public classTreeItem.classBinTree TI_BinTree = new classTreeItem.classBinTree();

        System.Windows.Forms.Timer tmrCursor = new System.Windows.Forms.Timer();
        #endregion

        #region EnumeratedTypes
        /// <summary>
        /// names of the Gui-FileDialog regions
        /// </summary>
        public enum enuRegions { Title, CurrentDirectory, DirTree, ContentCurrentDirectory, UserInput_Label, UserInput_TextInput, UserInput_Filter, UserInput_Confirm, UserInput_Cancel, Resize, _num };
        /// <summary>
        /// type of sub-regions used by the Sweep-and-Clean algorithm to determine what is located beneath the mouse cursor
        /// </summary>
        public enum enuSweepAndPruneObjectTypes { Region, ScrollBar, _num };
        enum enuState { UserInput, GrabAndMove, Resize, MultiSelect, _num };
        enum enuCursorState { Blink_On, Blink_Off, Off, _num };
        #endregion 

        #region Regions
        /// <summary>
        /// GUI-FileDialog Regions can be accessed using the enuRegion enumerated type
        /// </summary>
        public List<classRegion> lstRegions = new List<classRegion>();
        /// <summary>
        /// Current Directory Region
        /// </summary>
        public classRegion regCurrentDirectory = null;
        /// <summary>
        /// Directory Tree Region
        /// </summary>
        public classRegion regDirTree = null;
        /// <summary>
        /// current directory content Region
        /// </summary>
        public classRegion regContent = null;
        /// <summary>
        /// User-Input 'file' Label Region
        /// </summary>
        public classRegion regUserInput_Label = null;
        /// <summary>
        /// User-Input TextInput Region
        /// </summary>
        public classRegion regUserInput_TextInput = null;
        /// <summary>
        /// User-Input Filter Region
        /// </summary>
        public classRegion regUserInput_FilterInput = null;
        /// <summary>
        /// User-Input Confirm-button Region
        /// </summary>
        public classRegion regUserInput_Confirm = null;
        /// <summary>
        /// User-Input Cancel-button Region
        /// </summary>
        public classRegion regUserInput_Cancel = null;
        /// <summary>
        /// Title Region
        /// </summary>
        public classRegion regTitle = null;
        /// <summary>
        /// Resize Region
        /// </summary>
        public classRegion regResize = null;
        bool bolRegionsDefined = false;

        void mnuViewStyle_Click(object sender, EventArgs e)
        {
            MenuItem mnuSender = (MenuItem)sender;
            cTICurrent.eViewStyle = (classDraw_Content.enuViewStyle)mnuSender.Tag;
            regContent.IsRefreshed = false;
            DrawScreen();
        }

        void Regions_Define()
        {
            lstRegions.AddRange(new classRegion[(int)enuRegions._num]);

            CanBeResized = false;
            FileDialog_GUI cMyRef = this;
            // define default regions
            {
                BackColor = Color.White;

                //                  Title
                {
                    regTitle = new classRegion(enuRegions.Title, ref cMyRef);
                    regTitle.ScrollBarV_Shown =
                        regTitle.ScrollBarH_Shown
                        = false;
                    regTitle.ColorBackground = Color.Blue;
                    regTitle.ColorForeground = Color.White;
                    regTitle.IsFixedHeight
                        = regTitle.IsFixedWidth
                        = regTitle.IsFixedLeft
                        = regTitle.IsFixedTop
                        = true;
                    regTitle.Location = new Point(3, 3);
                    regTitle.size = new Size(Width - regTitle.rec.Left - 5, 25);
                }
                //                  Current Directory
                {
                    regCurrentDirectory = new classRegion(enuRegions.CurrentDirectory, ref cMyRef);
                    regCurrentDirectory.ScrollBarV_Shown
                        = regCurrentDirectory.ScrollBarH_Shown
                        = false;
                    regCurrentDirectory.IsFixedHeight
                        = regCurrentDirectory.IsFixedTop
                        = regCurrentDirectory.IsFixedLeft
                        = regCurrentDirectory.IsFixedWidth
                        = true;
                    regCurrentDirectory.Location = new Point(3, regTitle.rec.Bottom);
                    regCurrentDirectory.size = new Size(Width - regCurrentDirectory.rec.Left - 10, 20);
                }

                //                  Directory Tree
                {
                    regDirTree = new classRegion(enuRegions.DirTree, ref cMyRef);
                    regDirTree.IsFixedLeft
                        = regDirTree.IsFixedTop
                        = regDirTree.IsFixedWidth
                        = regDirTree.IsFixedHeight
                        = true;
                    regDirTree.Location = new Point(5, regCurrentDirectory.rec.Bottom);
                    regDirTree.size = new Size(Width / 2 - regDirTree.rec.Left, Height - regDirTree.rec.Top - 65);
                }

                //                  Content
                {
                    regContent = new classRegion(enuRegions.ContentCurrentDirectory, ref cMyRef);
                    regContent.IsFixedTop = true;
                    regContent.Location = new Point(regDirTree.rec.Right, regDirTree.rec.Top);
                    regContent.size = regDirTree.size;
                    regContent.ScrollBarV_Shown = false;
                }

                //                  user-input
                {
                    //                      Label
                    {
                        regUserInput_Label = new classRegion(enuRegions.UserInput_Label, ref cMyRef);
                        regUserInput_Label.ScrollBarV_Shown
                            = regUserInput_Label.ScrollBarH_Shown
                            = false;
                        regUserInput_Label.IsFixedHeight
                            = regUserInput_Label.IsFixedWidth
                            = regUserInput_Label.IsFixedLeft
                            = regUserInput_Label.IsFixedTop
                            = true;
                        regUserInput_Label.size = new Size(30, 20);
                        regUserInput_Label.Location = new Point(regDirTree.rec.Left, regDirTree.rec.Bottom);
                    }


                    //                     Filter & Text Input 
                    {
                        // define filter size
                        regUserInput_FilterInput = new classRegion(enuRegions.UserInput_Filter, ref cMyRef);
                        regUserInput_FilterInput.ScrollBarV_Shown
                            = regUserInput_FilterInput.ScrollBarH_Shown
                            = false;
                        regUserInput_FilterInput.IsFixedHeight
                            = regUserInput_FilterInput.IsFixedWidth
                            = regUserInput_FilterInput.IsFixedLeft
                            = regUserInput_FilterInput.IsFixedTop
                            = true;
                        regUserInput_FilterInput.size = new Size(50, 20);
                        regUserInput_FilterInput.ColorBackground = Color.White;
                        regUserInput_FilterInput.ColorForeground = Color.Black;

                        // define text size & location
                        regUserInput_TextInput = new classRegion(enuRegions.UserInput_TextInput, ref cMyRef);
                        regUserInput_TextInput.ScrollBarV_Shown
                            = regUserInput_TextInput.ScrollBarH_Shown
                            = false;
                        regUserInput_TextInput.IsFixedHeight
                            = regUserInput_TextInput.IsFixedWidth
                            = regUserInput_TextInput.IsFixedLeft
                            = regUserInput_TextInput.IsFixedTop
                            = true;
                        regUserInput_TextInput.size = new Size(2 * regDirTree.rec.Width - regUserInput_FilterInput.rec.Width, 20);
                        regUserInput_TextInput.Location = new Point(regUserInput_Label.rec.Left, regUserInput_Label.rec.Bottom);
                        regUserInput_TextInput.ColorBackground = Color.White;
                        regUserInput_TextInput.ColorForeground = Color.Black;

                        // define filter location
                        regUserInput_FilterInput.Location = new Point(regUserInput_TextInput.rec.Right, regUserInput_Label.rec.Bottom);
                    }

                    //                      Confirm Button
                    {
                        regUserInput_Confirm = new classRegion(enuRegions.UserInput_Confirm, ref cMyRef);
                        regUserInput_Confirm.ScrollBarV_Shown
                            = regUserInput_Confirm.ScrollBarH_Shown
                            = false;
                        regUserInput_Confirm.IsFixedHeight
                            = regUserInput_Confirm.IsFixedWidth
                            = regUserInput_Confirm.IsFixedLeft
                            = regUserInput_Confirm.IsFixedTop
                            = true;
                        regUserInput_Confirm.size = new Size(50, 20);
                        regUserInput_Confirm.Location = new Point(regUserInput_FilterInput.rec.Right - regUserInput_Confirm.size.Width, regUserInput_FilterInput.rec.Bottom);
                    }

                    //                      Cancel Button
                    {
                        regUserInput_Cancel = new classRegion(enuRegions.UserInput_Cancel, ref cMyRef);
                        regUserInput_Cancel.ScrollBarV_Shown
                            = regUserInput_Cancel.ScrollBarH_Shown
                            = false;
                        regUserInput_Cancel.IsFixedHeight
                            = regUserInput_Cancel.IsFixedWidth
                            = regUserInput_Cancel.IsFixedLeft
                            = regUserInput_Cancel.IsFixedTop
                            = true;
                        regUserInput_Cancel.size = new Size(50, 20);
                        regUserInput_Cancel.Location = new Point(regUserInput_Confirm.rec.Left - regUserInput_Cancel.rec.Width, regUserInput_Confirm.rec.Top);
                    }

                    //                      Resize 
                    {
                        regResize = new classRegion(enuRegions.Resize, ref cMyRef);
                        regResize.ScrollBarV_Shown
                            = regResize.ScrollBarH_Shown
                            = false;
                        regResize.ColorBackground = Color.Aqua;
                        regResize.IsFixedHeight
                            = regResize.IsFixedWidth
                            = true;
                        regResize.PercentageForm = new RectangleF(95, 95, 5, 5);
                        regResize.size = new Size(10, 10);
                        regResize.Anchor = new classAnchor();
                        regResize.Anchor.eAnchorPoint = classAnchor.enuAnchorPoints.BottomRight;
                        regResize.Anchor.ptRelToAnchorPoint = new Point(-regResize.size.Width, -regResize.size.Height);
                    }
                }
            }

            lstRegions[(int)enuRegions.Title] = regTitle;
            lstRegions[(int)enuRegions.CurrentDirectory] = regCurrentDirectory;
            lstRegions[(int)enuRegions.DirTree] = regDirTree;
            lstRegions[(int)enuRegions.ContentCurrentDirectory] = regContent;
            lstRegions[(int)enuRegions.UserInput_Label] = regUserInput_Label;
            lstRegions[(int)enuRegions.UserInput_TextInput] = regUserInput_TextInput;
            lstRegions[(int)enuRegions.UserInput_Filter] = regUserInput_FilterInput;
            lstRegions[(int)enuRegions.UserInput_Confirm] = regUserInput_Confirm;
            lstRegions[(int)enuRegions.UserInput_Cancel] = regUserInput_Cancel;
            lstRegions[(int)enuRegions.Resize] = regResize;

            bolRegionsDefined = true;
            resize();
        }
        #endregion

        /// <summary>
        /// FileDialog_Gui instantiation
        /// </summary>
        public FileDialog_GUI()
        {
            if (instance == null)
                instance = this;

            Controls.Add(txtInput);
            txtInput.KeyDown += TxtInput_KeyDown;
            txtInput.TextChanged += TxtInput_TextChanged;
            txtInput.GotFocus += TxtInput_GotFocus;
            txtInput.LostFocus += TxtInput_LostFocus;

            Controls.Add(txtLoseFocus);
            txtLoseFocus.KeyDown += TxtLoseFocus_KeyDown;

            tmrCursor.Interval = 500;
            tmrCursor.Tick += TmrCursor_Tick;

            Size = new Size(600, 500);
            Regions_Define();
            ContextMenu = cMnu;
            cMnu.Popup += CMnu_Popup;

            cDrawer_DirTree = new classDraw_DirTree(ref regDirTree);
            cDrawer_Content = new classDraw_Content(ref regContent);
            FileDialog_GUI cMyRef = this;
            cUserInputButtonDrawer = new classDraw_UserInput_Button(ref cMyRef);

            BuildDirTree();

            Activated += FileDialog_GUI_Activated;
            SizeChanged += FileDialog_GUI_SizeChanged;
            MouseDoubleClick += FileDialog_GUI_MouseDoubleClick;
            MouseDown += FileDialog_GUI_MouseDown;
            MouseUp += FileDialog_GUI_MouseUp;
            MouseLeave += FileDialog_GUI_MouseLeave;
            MouseMove += FileDialog_GUI_MouseMove;
            MouseWheel += FileDialog_GUI_MouseWheel;
            VisibleChanged += FileDialog_GUI_VisibleChanged;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CMnu_Popup(object sender, EventArgs e)
        {
            cMnu.MenuItems.Clear();
            MenuItem mnuView = new MenuItem("View");
            {
                for (int intStyleCounter = (int)classDraw_Content.enuViewStyle._num - 1; intStyleCounter >= 0; intStyleCounter--)
                {
                    classDraw_Content.enuViewStyle eViewStyle = (classDraw_Content.enuViewStyle)intStyleCounter;
                    MenuItem mnuViewStyle = new MenuItem(eViewStyle.ToString(), mnuViewStyle_Click);
                    mnuViewStyle.Tag = (object)eViewStyle;
                    mnuViewStyle.Checked = (cTICurrent.eViewStyle == eViewStyle);
                    mnuView.MenuItems.Add(mnuViewStyle);
                }
            }
            cMnu.MenuItems.Add(mnuView);
        }

        #region Files

        /// <summary>
        /// returns the File Extension appended to GUI-FileDialog data-files
        /// </summary>
        public static string FileExtension
        {
            get { return "fdGUI"; }
        }
        static BinaryFormatter formatter = new BinaryFormatter();
        static void cleanExtension(ref string strFileName)
        {
            int intIndexExtension = strFileName.LastIndexOf('.');
            if (intIndexExtension > 0)
                strFileName = strFileName.Substring(0, intIndexExtension);
            strFileName += "." + FileExtension;
        }

        /// <summary>
        /// Saves this instance of GUI-FileDialog to the specified file
        /// </summary>
        /// <param name="strFileName">name of file to which this instance of GUI-FileDialog will be saved</param>
        /// </summary>
        public void GUI_Save(string strFileName)
        {
            cleanExtension(ref strFileName);

            FileStream fs = new FileStream(strFileName, FileMode.Create);

            //                                                              FORM
            //                              size
            formatter.Serialize(fs, Width);
            formatter.Serialize(fs, Height);

            //                              colors
            Color_Save(ref fs, ForeColor);
            Color_Save(ref fs, BackColor);
            Color_Save(ref fs, clrTransparent);

            //                              image
            formatter.Serialize(fs, BackgroundImage != null);
            if (BackgroundImage != null)
                formatter.Serialize(fs, BackgroundImage);

            //                                                              REGIONs
            for (int intRegionCounter = 0; intRegionCounter < (int)enuRegions.Resize; intRegionCounter++)
            {
                classRegion cRegion = lstRegions[intRegionCounter];
                //                          size
                formatter.Serialize(fs, cRegion.rec.Width);
                formatter.Serialize(fs, cRegion.rec.Height);
                //                          Location
                formatter.Serialize(fs, cRegion.rec.Left);
                formatter.Serialize(fs, cRegion.rec.Top);
                //                          colors
                Color_Save(ref fs, cRegion.ColorForeground);
                Color_Save(ref fs, cRegion.ColorBackground);

                //                          Font
                formatter.Serialize(fs, cRegion.font.Name);
                formatter.Serialize(fs, cRegion.font.Bold);
                formatter.Serialize(fs, cRegion.font.Italic);
                formatter.Serialize(fs, cRegion.font.Underline);
                formatter.Serialize(fs, cRegion.font.Strikeout);
                formatter.Serialize(fs, cRegion.font.Size);

                //                          blend
                formatter.Serialize(fs, cRegion.BlendBackground);
            }

            fs.Close();
        }

        /// <summary>
        /// Loads a GUI-FileDialog data file from storage and sets this instance appearance to it
        /// </summary>
        /// <param name="strFileName">name of file to be loaded</param>
        public void GUI_Load(string strFileName)
        {
            bolDrawScreen_Ignore = true;

            cleanExtension(ref strFileName);
            FileStream fs = new FileStream(strFileName, FileMode.Open);

            //                                                              FORM
            //                              size
            Width = (int)formatter.Deserialize(fs);
            Height = (int)formatter.Deserialize(fs);

            //                              colors
            ForeColor = Color_Load(ref fs);
            BackColor = Color_Load(ref fs);
            clrTransparent = Color_Load(ref fs);

            //                              image
            bool bolBackgroundImage = (bool)formatter.Deserialize(fs);
            if (bolBackgroundImage)
                BackgroundImage = (Bitmap)formatter.Deserialize(fs);

            //                                                              REGIONs
            for (int intRegionCounter = 0; intRegionCounter < (int)enuRegions.Resize; intRegionCounter++)
            {
                enuRegions eRegion = (enuRegions)intRegionCounter;
                classRegion cRegion = lstRegions[intRegionCounter];
                //                          size
                int intWidth = (int)formatter.Deserialize(fs);
                int intHeight = (int)formatter.Deserialize(fs);

                //                          Location
                int intLeft = (int)formatter.Deserialize(fs);
                int intTop = (int)formatter.Deserialize(fs);
                cRegion.rec = new Rectangle(new Point(intLeft, intTop), new Size(intWidth, intHeight));

                cRegion.cSweepAndPrune.lstElements.Clear();

                //                          colors
                cRegion.ColorForeground = Color_Load(ref fs);
                cRegion.ColorBackground = Color_Load(ref fs);


                //                          Font
                string strFont_FamilyName = (string)formatter.Deserialize(fs);
                bool bolFontBold = (bool)formatter.Deserialize(fs);
                bool bolFontItalic = (bool)formatter.Deserialize(fs);
                bool bolFontUnderline = (bool)formatter.Deserialize(fs);
                bool bolFontStrikeOut = (bool)formatter.Deserialize(fs);
                float fltFontSize = (float)formatter.Deserialize(fs);

                FontStyle fntStyle = (bolFontBold ? FontStyle.Bold : FontStyle.Regular)
                                        |
                                     (bolFontItalic ? FontStyle.Italic : FontStyle.Regular)
                                        |
                                     (bolFontUnderline ? FontStyle.Underline : FontStyle.Regular)
                                        |
                                     (bolFontStrikeOut ? FontStyle.Strikeout : FontStyle.Regular);

                cRegion.font = new Font(strFont_FamilyName, fltFontSize, fntStyle);

                //                          blend
                cRegion.BlendBackground = (bool)formatter.Deserialize(fs);
            }

            fs.Close();
            CurrentDirectory = System.IO.Directory.GetCurrentDirectory();
            cDrawer_DirTree.Refreshed = false;
            bolDrawScreen_Ignore = false;
            DrawScreen(true);
        }
        /// <summary>
        /// loads GUI-FileDialog data file from App. list of resources in a memory stream
        /// </summary>
        /// <param name="bytMemoryStream">name of memory stream to be loaded</param>
        public void GUI_Load(byte[] bytMemoryStream)
        {
            bolDrawScreen_Ignore = true;
            MemoryStream ms = new MemoryStream(bytMemoryStream);

            //                                                              FORM
            //                              size
            Width = (int)formatter.Deserialize(ms);
            Height = (int)formatter.Deserialize(ms);

            //                              colors
            ForeColor = Color_Load(ref ms);
            BackColor = Color_Load(ref ms);
            clrTransparent = Color_Load(ref ms);

            //                              image
            bool bolBackgroundImage = (bool)formatter.Deserialize(ms);
            if (bolBackgroundImage)
                BackgroundImage = (Bitmap)formatter.Deserialize(ms);

            //                                                              REGIONs
            for (int intRegionCounter = 0; intRegionCounter < (int)enuRegions.Resize; intRegionCounter++)
            {
                enuRegions eRegion = (enuRegions)intRegionCounter;
                classRegion cRegion = lstRegions[intRegionCounter];
                //                          size
                int intWidth = (int)formatter.Deserialize(ms);
                int intHeight = (int)formatter.Deserialize(ms);

                //                          Location
                int intLeft = (int)formatter.Deserialize(ms);
                int intTop = (int)formatter.Deserialize(ms);
                cRegion.rec = new Rectangle(new Point(intLeft, intTop), new Size(intWidth, intHeight));

                cRegion.cSweepAndPrune.lstElements.Clear();

                //                          colors
                cRegion.ColorForeground = Color_Load(ref ms);
                cRegion.ColorBackground = Color_Load(ref ms);


                //                          Font
                string strFont_FamilyName = (string)formatter.Deserialize(ms);
                bool bolFontBold = (bool)formatter.Deserialize(ms);
                bool bolFontItalic = (bool)formatter.Deserialize(ms);
                bool bolFontUnderline = (bool)formatter.Deserialize(ms);
                bool bolFontStrikeOut = (bool)formatter.Deserialize(ms);
                float fltFontSize = (float)formatter.Deserialize(ms);

                FontStyle fntStyle = (bolFontBold ? FontStyle.Bold : FontStyle.Regular)
                                            |
                                        (bolFontItalic ? FontStyle.Italic : FontStyle.Regular)
                                            |
                                        (bolFontUnderline ? FontStyle.Underline : FontStyle.Regular)
                                            |
                                        (bolFontStrikeOut ? FontStyle.Strikeout : FontStyle.Regular);

                cRegion.font = new Font(strFont_FamilyName, fltFontSize, fntStyle);

                //                          blend
                cRegion.BlendBackground = (bool)formatter.Deserialize(ms);

                cRegion.bmp = null;
                //cRegion.bmpHighlight = null;

                cRegion.IsRefreshed = false;
            }

            ms.Close();
            CurrentDirectory = System.IO.Directory.GetCurrentDirectory();
            cDrawer_DirTree.Refreshed = false;
            resize();

            bolDrawScreen_Ignore = false;
            DrawScreen(true);
        }

        /// <summary>
        /// saves a color value to a specified FileStream
        /// </summary>
        void Color_Save(ref FileStream fs, Color clr)
        {
            formatter.Serialize(fs, (int)clr.A);
            formatter.Serialize(fs, (int)clr.R);
            formatter.Serialize(fs, (int)clr.G);
            formatter.Serialize(fs, (int)clr.B);
        }

        /// <summary>
        /// returns a Color loaded from a specified FileStream
        /// </summary>
        Color Color_Load(ref FileStream fs)
        {
            int intA = (int)formatter.Deserialize(fs);
            int intR = (int)formatter.Deserialize(fs);
            int intG = (int)formatter.Deserialize(fs);
            int intB = (int)formatter.Deserialize(fs);

            Color clrRetVal = Color.FromArgb(intA, intR, intG, intB);
            return clrRetVal;
        }

        /// <summary>
        /// returns a Color loaded from a specified MemoryStream
        /// </summary>
        Color Color_Load(ref MemoryStream ms)
        {
            int intA = (int)formatter.Deserialize(ms);
            int intR = (int)formatter.Deserialize(ms);
            int intG = (int)formatter.Deserialize(ms);
            int intB = (int)formatter.Deserialize(ms);

            Color clrRetVal = Color.FromArgb(intA, intR, intG, intB);
            return clrRetVal;
        }

        #endregion

        #region Events

        bool bolActivated = false;
        /// <summary>
        /// first function executed after instantiation - is only executed once
        /// </summary>
        private void FileDialog_GUI_Activated(object sender, EventArgs e)
        {
            if (bolActivated) return;
            bolActivated = true;
            txtLoseFocus.Focus();
            resize();
            DrawScreen(true);
        }

        /// <summary>
        /// centers the form when its visible Property is changed
        /// </summary>
        private void FileDialog_GUI_VisibleChanged(object sender, EventArgs e)
        {
            Left = (Screen.PrimaryScreen.WorkingArea.Width - Width) / 2;
            Top = (Screen.PrimaryScreen.WorkingArea.Height - Height) / 2;
            return;
        }

        /// <summary>
        /// Timer Event that animates the cursor in the User-Input TextInput Region
        /// </summary>
        private void TmrCursor_Tick(object sender, EventArgs e)
        {
            switch (eCursorState)
            {
                case enuCursorState.Off:
                    {
                        eCursorState = txtInput.SelectionLength == 0 ? enuCursorState.Blink_On : enuCursorState.Off;
                        if (regUserInput_TextInput.Highlight)
                            DrawScreen();
                    }
                    break;

                default:
                    {
                        eCursorState = (enuCursorState)(((int)eCursorState + 1) % 2);
                        regUserInput_TextInput.IsRefreshed = false;
                        DrawScreen();
                    }
                    break;
            }
        }

        /// <summary>
        /// txtLoseFocus takes the focus when txtInput(needed to input text in the UserInput_TextInput GUI textbox) loses focus.
        /// with this KeyDown event while focus is away from the UserInput_TextInput GUI textbox allows the user to Confirm a 
        /// selected file if ENTER is pressed while mouse is over the CurrentDirectoryContent region
        /// </summary>
        private void TxtLoseFocus_KeyDown(object sender, KeyEventArgs e)
        {
            if (cRegionUnderMouse == regContent)
            {
                switch (e.KeyCode)
                {
                    case Keys.Enter:
                        {
                            confirm();
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// when the user shifts Focus away from the UserInput_TextInput Region by clicking on anything other than that region
        /// focus is given to txtLoseFocus & the Timer which animates the UserInput_TextInput Cursor is disabled
        /// </summary>
        private void TxtInput_LostFocus(object sender, EventArgs e)
        {
            tmrCursor.Enabled = false;
        }

        /// <summary>
        /// when the UserInput_TextInput Region is selected - Focus is given to the txtInput textbox to receive user's typed input
        /// and the Timer which animates the UserInput_TextInput's cursor is enabled
        /// </summary>
        private void TxtInput_GotFocus(object sender, EventArgs e)
        {
            tmrCursor.Enabled = true;// txtInput.SelectionLength == 0;
        }

        /// <summary>
        /// txtInput is Focused only when the User has selected the UserInput_TextInput Region
        /// This event is triggered when the UserInput_TextInput Region's text is altered
        /// </summary>
        private void TxtInput_TextChanged(object sender, EventArgs e)
        {
            regUserInput_TextInput.IsRefreshed = false;
            regContent.IsRefreshed = false;
            DrawScreen();
        }

        /// <summary>
        /// txtInput is Focused only when the User has selected the UserInput_TextInput Region
        /// This event is triggered when the user is typing into the UserInput_TextInput Region
        /// </summary>
        private void TxtInput_KeyDown(object sender, KeyEventArgs e)
        {
            string strForbiddenChar = "/\\:*?><|";
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    {
                        lstFiles.Clear();
                        lstFiles.Add(txtInput.Text);
                        confirm();
                    }
                    break;

                case Keys.Home:
                case Keys.End:
                case Keys.Left:
                case Keys.Right:
                    {
                        regUserInput_TextInput.Highlight = true;
                    }
                    break;

                default:
                    {
                        char chrPressed = (char)e.KeyCode;
                        if (strForbiddenChar.Contains(chrPressed))
                            e.SuppressKeyPress = true;
                    }
                    break;
            }
            eCursorState = (txtInput.SelectionLength == 0 ? enuCursorState.Blink_On : enuCursorState.Off);
        }

        /// <summary>
        /// this mouse-wheel event is triggered over the form and handles the MouseWheel events for all the GUI-FileDialog's regions and scroll-bars
        /// </summary>
        private void FileDialog_GUI_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta == 0) return;
            classSweepAndPrune.classElement cSPEle = cSweepAndPrune.Search(new Point(e.X, e.Y));
            if (cSPEle != null)
            {
                enuSweepAndPruneObjectTypes eSWObjectType = (enuSweepAndPruneObjectTypes)cSPEle.tag;
                switch (eSWObjectType)
                {
                    case enuSweepAndPruneObjectTypes.Region:
                        {
                            classRegion cRegionUnderMouse = (classRegion)cSPEle.obj;

                            switch (cRegionUnderMouse.Region)
                            {
                                case enuRegions.UserInput_Filter:
                                    {
                                        if (e.Delta < 0 && FilterIndex > 1)
                                            FilterIndex = FilterIndex - 1;
                                        else if (e.Delta > 0 && FilterIndex <= lstFilters.Count)
                                            FilterIndex = FilterIndex + 1;
                                    }
                                    break;

                                default:
                                    {
                                        if (cRegionUnderMouse != null)
                                        {
                                            if (cRegionUnderMouse.ScrollBar_V)
                                            {
                                                cRegionUnderMouse.Scroll_V((double)(-Math.Abs(e.Delta) / e.Delta * cRegionUnderMouse.cScrollBarV.Step_Small));
                                                DrawScreen();
                                            }
                                            else if (cRegionUnderMouse.ScrollBar_H)
                                            {
                                                cRegionUnderMouse.Scroll_H((double)(-Math.Abs(e.Delta) / e.Delta * cRegionUnderMouse.cScrollBarH.Step_Small));
                                                DrawScreen();
                                            }
                                        }

                                    }
                                    break;
                            }
                        }
                        break;

                    case enuSweepAndPruneObjectTypes.ScrollBar:
                        {
                            classScrollBar cScrollBar_UnderMouse = (classScrollBar)cSPEle.obj;
                            switch (cScrollBar_UnderMouse.eType)
                            {
                                case classScrollBar.enuScrollBarType.Horizontal:
                                    {
                                        cScrollBar_UnderMouse.cParent.Scroll_H((double)(-Math.Abs(e.Delta) / e.Delta * cScrollBar_UnderMouse.Step_Small));
                                        DrawScreen();
                                    }
                                    break;

                                case classScrollBar.enuScrollBarType.Vertical:
                                    {
                                        cScrollBar_UnderMouse.cParent.Scroll_V((double)(-Math.Abs(e.Delta) / e.Delta * cScrollBar_UnderMouse.Step_Small));
                                        DrawScreen();
                                    }
                                    break;
                            }
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// Resets Interface variables to idle condition when the Mouse leaves the form
        /// </summary>
        private void FileDialog_GUI_MouseLeave(object sender, EventArgs e)
        {
            eState = enuState.UserInput;
            bool bolDrawScreen = (cRegionUnderMouse != null || cBtnUnderMouse != null);

            if (cRegionUnderMouse != null)
            {
                cRegionUnderMouse = null;
            }

            if (cBtnUnderMouse != null)
            {
                cBtnUnderMouse.HighLight = cBtnUnderMouse.Toggled;
                cBtnUnderMouse.Refreshed = false;
                cBtnUnderMouse = null;
            }
            if (bolDrawScreen)
                DrawScreen();
        }

        /// <summary>
        /// resets ScrollBarGrabs, GrabAndMove, Resize & Multiselect controls when the MouseButton is released
        /// </summary>
        private void FileDialog_GUI_MouseUp(object sender, MouseEventArgs e)
        {
            if (cScrollBarUnderMouse != null)
                cScrollBarUnderMouse.Grab = false;

            switch (eState)
            {
                case enuState.GrabAndMove:
                case enuState.Resize:
                case enuState.MultiSelect:
                    {
                        eState = enuState.UserInput;
                    }
                    break;

                case enuState.UserInput:
                    {
                    }
                    break;
            }
        }

        /// <summary>
        /// determines what Region, ScrollBar or Button is beneath the MouseCursor when the Mouse is moved over the form
        /// </summary>
        private void FileDialog_GUI_MouseMove(object sender, MouseEventArgs e)
        {
            semMouseMove.WaitOne();
            Point ptForm = new Point(e.X, e.Y);
            if (cScrollBarUnderMouse != null && cScrollBarUnderMouse.Grab)
                goto handle_SlideScrollBar;

            cSweepPruneEle_UnderMouse = cSweepAndPrune.Search(ptForm);

            if (cSweepPruneEle_UnderMouse != null)
            {
                enuSweepAndPruneObjectTypes eSWObjectType = (enuSweepAndPruneObjectTypes)cSweepPruneEle_UnderMouse.tag;
                switch (eSWObjectType)
                {
                    case enuSweepAndPruneObjectTypes.Region:
                        {
                            cScrollBarUnderMouse = null;
                            cRegionUnderMouse = (classRegion)cSweepPruneEle_UnderMouse.obj;
                            if (cRegionUnderMouse != null)
                            {
                                if (cRegionUnderMouse.cSweepAndPrune != null)
                                {
                                    Point ptRegion = new Point(e.X - cRegionUnderMouse.rec.Left + cRegionUnderMouse.recVisible.Left,
                                                               e.Y - cRegionUnderMouse.rec.Top + cRegionUnderMouse.recVisible.Top);
                                    classSweepAndPrune.classElement cEle_Button = cRegionUnderMouse.cSweepAndPrune.Search(ptRegion);
                                    if (cEle_Button != null)
                                    {
                                        classButton cBtnUnderMouse_New = (classButton)cEle_Button.obj;
                                        if (cBtnUnderMouse != cBtnUnderMouse_New)
                                        {
                                            cBtnUnderMouse = cBtnUnderMouse_New;
                                            cBtnUnderMouse.HighLight = true;
                                            if (cRegionUnderMouse.Region == enuRegions.DirTree)
                                            {
                                                classTreeItem cTI_UnderMouse = (classTreeItem)cBtnUnderMouse.obj;
                                            }
                                            DrawScreen();
                                        }
                                    }
                                    else
                                    {
                                        if (cBtnUnderMouse != null)
                                        {
                                            cBtnUnderMouse = null;
                                            DrawScreen();
                                        }
                                    }
                                }
                            }
                        }
                        break;

                    case enuSweepAndPruneObjectTypes.ScrollBar:
                        {
                            cScrollBarUnderMouse = (classScrollBar)cSweepPruneEle_UnderMouse.obj;
                            if (cScrollBarUnderMouse != null)
                            {
                                if (cScrollBarUnderMouse.Grab)
                                    goto handle_SlideScrollBar;
                            }
                        }
                        break;
                }
            }
            else
            {
                if (cBtnUnderMouse != null)
                    cBtnUnderMouse = null;
                if (RegionUnderMouse != null)
                    cRegionUnderMouse = null;
                DrawScreen();
            }

            switch (eState)
            {
                case enuState.GrabAndMove:
                    {
                        Location = new Point(MousePosition.X - ptGrab.X,
                                             MousePosition.Y - ptGrab.Y);
                    }
                    break;

                case enuState.MultiSelect:
                    {
                        if (cRegionUnderMouse != null && cRegionUnderMouse.Region == enuRegions.ContentCurrentDirectory)
                        {
                            if (cRegionUnderMouse.cSweepAndPrune != null)
                            {
                                ptMultiSelect_Current = new Point(e.X - cRegionUnderMouse.rec.Left + cRegionUnderMouse.recVisible.Left,
                                                                  e.Y - cRegionUnderMouse.rec.Top + cRegionUnderMouse.recVisible.Top);
                                {
                                    Rectangle recSearch = RectangleFromTwoPoints(ptMultiSelect_Current, ptMultiSelect_Grab);
                                    List<classSweepAndPrune.classElement> lstSearchResults = cRegionUnderMouse.cSweepAndPrune.Search(recSearch);

                                    for (int intCounter = 0; intCounter < lstButtonsSelected.Count; intCounter++)
                                    {
                                        lstButtonsSelected[intCounter].Toggled = false;
                                        lstButtonsSelected[intCounter].Refreshed = false;
                                    }
                                    lstButtonsSelected.Clear();
                                    lstFiles.Clear();
                                    for (int intCounter = 0; intCounter < lstSearchResults.Count; intCounter++)
                                    {
                                        classSweepAndPrune.classElement cEle = lstSearchResults[intCounter];
                                        classButton cBtn = (classButton)cEle.obj;
                                        classTreeItem cTI = (classTreeItem)cBtn.obj;
                                        if (cTI.eTreeItemType == classTreeItem.enuTreeItemType.file)
                                        {
                                            cBtn.Toggled = true;
                                            lstFiles.Add(cTI.strPath);
                                            lstButtonsSelected.Add(cBtn);
                                        }
                                    }
                                    cRegionUnderMouse.Highlight = true;
                                    DrawScreen();
                                }
                            }
                        }
                        else
                            eState = enuState.UserInput;
                    }
                    break;

                case enuState.Resize:
                    {
                        Point ptRelScreen_Current = MousePosition;
                        Point ptCenterForm = new Point(Width / 2, Height / 2);
                        Point ptCenterFormRelScreen = new Point(Left + Width / 2, Top + Height / 2);

                        Point ptSigns = new Point(ptGrab.X < ptCenterForm.X ? -1 : 1,
                                                  ptGrab.Y < ptCenterForm.Y ? -1 : 1);
                        Size szDelta = new Size(ptSigns.X * 2 * (ptRelScreen_Current.X - ptRelativeToScreen_Grab.X),
                                                ptSigns.Y * 2 * (ptRelScreen_Current.Y - ptRelativeToScreen_Grab.Y));
                        Size szNew = new Size(Width + szDelta.Width, Height + szDelta.Height);

                        Point ptLocation = new Point(ptCenterFormRelScreen.X - szNew.Width / 2, ptCenterFormRelScreen.Y - szNew.Height / 2);

                        if (ptLocation.X < 0)
                        {
                            ptLocation.X = 0;
                            szNew.Width -= szDelta.Width / 2;
                        }

                        if (ptLocation.X + szNew.Width > Screen.PrimaryScreen.WorkingArea.Width)
                        {
                            int intExcess = (ptLocation.X + szNew.Width - Screen.PrimaryScreen.WorkingArea.Width);
                            ptLocation.X -= intExcess;
                            szNew.Width -= intExcess;
                        }

                        if (ptLocation.Y < 0)
                        {
                            ptLocation.Y = 0;
                            szNew.Height -= szDelta.Height / 2;
                        }

                        if (ptLocation.Y + szNew.Height > Screen.PrimaryScreen.WorkingArea.Height)
                        {
                            int intExcess = (ptLocation.Y + szNew.Height - Screen.PrimaryScreen.WorkingArea.Height);
                            ptLocation.Y -= intExcess;
                            szNew.Height -= intExcess;
                        }

                        Size = szNew;
                        Location = ptLocation;

                        ptRelativeToScreen_Grab = ptRelScreen_Current;
                    }
                    break;

                case enuState.UserInput:
                    {
                        if (cSweepPruneEle_UnderMouse != null)
                        {
                            enuSweepAndPruneObjectTypes eSWObjectType = (enuSweepAndPruneObjectTypes)cSweepPruneEle_UnderMouse.tag;
                            switch (eSWObjectType)
                            {
                                case enuSweepAndPruneObjectTypes.Region:
                                    {
                                        cRegionUnderMouse = (classRegion)cSweepPruneEle_UnderMouse.obj;
                                    }
                                    break;

                                case enuSweepAndPruneObjectTypes.ScrollBar:
                                    {
                                        classScrollBar cScrollBarUnderMouse = (classScrollBar)cSweepPruneEle_UnderMouse.obj;
                                    }
                                    break;
                            }
                        }
                    }
                    break;
            }

            semMouseMove.Release();
            return;
            handle_SlideScrollBar:
            Point ptScrollBar = new Point(ptForm.X - cScrollBarUnderMouse.recArea.Left, ptForm.Y - cScrollBarUnderMouse.recArea.Top);

            int intDifference = cScrollBarUnderMouse.eType == classScrollBar.enuScrollBarType.Horizontal
                                        ? cScrollBarUnderMouse.ptGrab.X - ptScrollBar.X
                                        : cScrollBarUnderMouse.ptGrab.Y - ptScrollBar.Y;

            double dblDifference = cScrollBarUnderMouse.eType == classScrollBar.enuScrollBarType.Horizontal
                                        ? (double)intDifference / (double)((double)(1.0 - cScrollBarUnderMouse.Step_Large) * cScrollBarUnderMouse.recArea.Width)
                                        : (double)intDifference / (double)((double)(1.0 - cScrollBarUnderMouse.Step_Large) * cScrollBarUnderMouse.recArea.Height);
            cScrollBarUnderMouse.ptGrab = ptScrollBar;
            cScrollBarUnderMouse.Value -= dblDifference;
            if (cScrollBarUnderMouse.cParent.Region == enuRegions.ContentCurrentDirectory)
            {
                classRegion cRegContent = cScrollBarUnderMouse.cParent;
                //cRegContent.fd_Parent.cDrawer_Content.DrawButtonsOnScreen(cRegContent.fd_Parent.cTICurrent.eViewStyle);
            }
            DrawScreen();
            semMouseMove.Release();
        }

        /// <summary>
        /// sets control variables in response to the MouseButton being pressed by the user
        /// </summary>
        private void FileDialog_GUI_MouseDown(object sender, MouseEventArgs e)
        {
            if (cSweepPruneEle_UnderMouse != null)
            {
                enuSweepAndPruneObjectTypes eSWObjectType = (enuSweepAndPruneObjectTypes)cSweepPruneEle_UnderMouse.tag;
                switch (eSWObjectType)
                {
                    case enuSweepAndPruneObjectTypes.Region:
                        {
                            classRegion cRegUnderMouse_New = (classRegion)cSweepPruneEle_UnderMouse.obj;
                            if (cRegionUnderMouse != regUserInput_TextInput)
                                txtLoseFocus.Focus();

                            cRegionUnderMouse = cRegUnderMouse_New;

                            if (cRegionUnderMouse != null)
                            {
                                switch (cRegionUnderMouse.Region)
                                {
                                    case enuRegions.Title:
                                        {
                                            eState = enuState.GrabAndMove;
                                            ptGrab = new Point(e.X, e.Y);
                                        }
                                        break;

                                    case enuRegions.DirTree:
                                        {
                                            if (cRegionUnderMouse.cSweepAndPrune != null)
                                            {
                                                Point ptRegion = new Point(e.X - cRegionUnderMouse.rec.Left + cRegionUnderMouse.recVisible.Left,
                                                                           e.Y - cRegionUnderMouse.rec.Top + cRegionUnderMouse.recVisible.Top);
                                                classSweepAndPrune.classElement cEle_Button = cRegionUnderMouse.cSweepAndPrune.Search(ptRegion);
                                                if (cEle_Button != null)
                                                {
                                                    cBtnUnderMouse = (classButton)cEle_Button.obj;
                                                    cBtnUnderMouse.HighLight = true;
                                                    classTreeItem cTI_UnderMouse = (classTreeItem)cBtnUnderMouse.obj;
                                                    cRegionUnderMouse.Highlight = true;
                                                    switch (cBtnUnderMouse.eButtonType)
                                                    {
                                                        case classButton.enuButtonType.ExpandCollapse:
                                                            {
                                                                bolDrawScreen_Ignore = true;
                                                                cTI_UnderMouse.Expanded = !cTI_UnderMouse.Expanded;
                                                                bolDrawScreen_Ignore = false;
                                                                DrawScreen();
                                                            }
                                                            break;

                                                        case classButton.enuButtonType.Directory:
                                                            {
                                                                if (cTICurrent == cTI_UnderMouse)
                                                                {
                                                                    bolDrawScreen_Ignore = true;
                                                                    cTICurrent.Expanded = !cTICurrent.Expanded;
                                                                    bolDrawScreen_Ignore = false;
                                                                    DrawScreen();
                                                                }
                                                                else
                                                                {
                                                                    bolDrawScreen_Ignore = true;
                                                                    cTICurrent = cTI_UnderMouse;
                                                                    CurrentDirectory = cTI_UnderMouse.strPath;
                                                                    bolDrawScreen_Ignore = false;
                                                                    DrawScreen();
                                                                }
                                                            }
                                                            break;
                                                    }
                                                }
                                            }
                                        }
                                        break;

                                    case enuRegions.ContentCurrentDirectory:
                                        {
                                            if (cRegionUnderMouse.cSweepAndPrune != null)
                                            {
                                                Point ptRegion = new Point(e.X - cRegionUnderMouse.rec.Left + cRegionUnderMouse.recVisible.Left,
                                                                           e.Y - cRegionUnderMouse.rec.Top + cRegionUnderMouse.recVisible.Top);
                                                classSweepAndPrune.classElement cEle_Button = cRegionUnderMouse.cSweepAndPrune.Search(ptRegion);
                                                if (MultiSelect)
                                                {
                                                    eState = enuState.MultiSelect;
                                                    ptMultiSelect_Grab = ptRegion;
                                                }

                                                if (cEle_Button != null)
                                                {
                                                    cBtnUnderMouse = (classButton)cEle_Button.obj;
                                                    classTreeItem cTI_UnderMouse = (classTreeItem)cBtnUnderMouse.obj;
                                                    switch (cBtnUnderMouse.eButtonType)
                                                    {
                                                        case classButton.enuButtonType.File:
                                                            {
                                                                cBtnUnderMouse.Toggle();
                                                                if (cBtnUnderMouse.Toggled)
                                                                {
                                                                    lstButtonsSelected.Clear();
                                                                    cRegionUnderMouse.btnSelected = cBtnUnderMouse;
                                                                    lstButtonsSelected.Add(cBtnUnderMouse);

                                                                    cRegionUnderMouse.IsRefreshed = false;
                                                                    cRegionUnderMouse.cSweepAndPrune.Reset();
                                                                }
                                                                else
                                                                    lstButtonsSelected.Remove(cBtnUnderMouse);
                                                                if (!MultiSelect)
                                                                {
                                                                    lstFiles.Clear();
                                                                    lstFiles.Add(cTI_UnderMouse.strPath);
                                                                }
                                                                txtInput.Tag = (object)cTI_UnderMouse.strPath;
                                                                txtInput.Text = cTI_UnderMouse.strName;
                                                            }
                                                            break;
                                                    }
                                                    DrawScreen();
                                                }
                                            }

                                        }
                                        break;

                                    case enuRegions.UserInput_Cancel:
                                        {
                                            if (OverrideConfirmCancel) return;
                                            if (event_Cancel != null)
                                                event_Cancel((object)this, new EventArgs());
                                            DialogResult = DialogResult.Cancel;
                                            Hide();
                                        }
                                        break;

                                    case enuRegions.UserInput_Confirm:
                                        {
                                            if (OverrideConfirmCancel) return;
                                            confirm();
                                        }
                                        break;

                                    case enuRegions.UserInput_TextInput:
                                        {
                                            if (txtInput.Focused)
                                            {
                                                Point ptRegion = new Point(e.X - cRegionUnderMouse.rec.Left + cRegionUnderMouse.recVisible.Left,
                                                                           e.Y - cRegionUnderMouse.rec.Top + cRegionUnderMouse.recVisible.Top);
                                                classSweepAndPrune.classElement cEle_Button = cRegionUnderMouse.cSweepAndPrune.Search(ptRegion);

                                                if (cEle_Button != null)
                                                {
                                                    cBtnUnderMouse = (classButton)cEle_Button.obj;
                                                    classTreeItem cTI_UnderMouse = (classTreeItem)cBtnUnderMouse.obj;
                                                    txtInput.SelectionStart = cRegionUnderMouse.cSweepAndPrune.lstElements.IndexOf(cEle_Button);
                                                    txtInput.SelectionLength = 0;
                                                    DrawScreen();
                                                }
                                                else
                                                {
                                                    txtInput.SelectionStart = txtInput.Text.Length;
                                                    txtInput.SelectionLength = 0;
                                                    DrawScreen();
                                                }

                                            }
                                            else
                                            {
                                                txtInput.Focus();
                                                txtInput.SelectionStart = 0;
                                                txtInput.SelectionLength = txtInput.Text.Length;
                                            }
                                        }
                                        break;

                                    case enuRegions.Resize:
                                        {
                                            eState = enuState.Resize;
                                            ptGrab = new Point(e.X, e.Y);
                                            ptRelativeToScreen_Grab = MousePosition;
                                        }
                                        break;
                                }
                            }
                        }
                        break;

                    case enuSweepAndPruneObjectTypes.ScrollBar:
                        {
                            cScrollBarUnderMouse = (classScrollBar)cSweepPruneEle_UnderMouse.obj;

                            Point ptOnScrollBar = new Point(e.X - cScrollBarUnderMouse.recArea.Left, e.Y - cScrollBarUnderMouse.recArea.Top);

                            classSweepAndPrune.classElement cEle_ScrollBar_UnderMouse = cScrollBarUnderMouse.cSweepAndPrune.Search(ptOnScrollBar);
                            if (cEle_ScrollBar_UnderMouse != null)
                            {
                                classScrollBar.enuScrollBar_Regions eScrollBarRegion_Clicked = (classScrollBar.enuScrollBar_Regions)cEle_ScrollBar_UnderMouse.obj;
                                switch (eScrollBarRegion_Clicked)
                                {
                                    case classScrollBar.enuScrollBar_Regions.BeforeSlider:
                                        {
                                            switch (cScrollBarUnderMouse.eType)
                                            {
                                                case classScrollBar.enuScrollBarType.Horizontal:
                                                    {

                                                        cScrollBarUnderMouse.cParent.Scroll_H((double)((cScrollBarUnderMouse.Step_Large > 0.5 ? -2 : -1) * cScrollBarUnderMouse.Step_Large));
                                                    }
                                                    break;

                                                case classScrollBar.enuScrollBarType.Vertical:
                                                    {
                                                        cScrollBarUnderMouse.cParent.Scroll_V((double)((cScrollBarUnderMouse.Step_Large > 0.5 ? -2 : -1) * cScrollBarUnderMouse.Step_Large));
                                                    }
                                                    break;
                                            }
                                            DrawScreen();
                                        }
                                        break;

                                    case classScrollBar.enuScrollBar_Regions.Slider:
                                        {
                                            // grab slider
                                            Point ptScrollBar = new Point(e.X - cSweepPruneEle_UnderMouse.rec.Left, e.Y - cSweepPruneEle_UnderMouse.rec.Top);
                                            cScrollBarUnderMouse.ptGrab = ptScrollBar;//  new Point(ptScrollBar.X - cEle_ScrollBar_UnderMouse.rec.Left, ptScrollBar.Y - cEle_ScrollBar_UnderMouse.rec.Top);
                                            cScrollBarUnderMouse.Grab = true;
                                        }
                                        break;

                                    case classScrollBar.enuScrollBar_Regions.AfterSlider:
                                        {
                                            switch (cScrollBarUnderMouse.eType)
                                            {
                                                case classScrollBar.enuScrollBarType.Horizontal:
                                                    {
                                                        cScrollBarUnderMouse.cParent.Scroll_H((double)((cScrollBarUnderMouse.Step_Large > 0.5 ? 2 : 1) * cScrollBarUnderMouse.Step_Large));
                                                    }
                                                    break;

                                                case classScrollBar.enuScrollBarType.Vertical:
                                                    {
                                                        cScrollBarUnderMouse.cParent.Scroll_V((double)((cScrollBarUnderMouse.Step_Large > 0.5 ? 2 : 1) * cScrollBarUnderMouse.Step_Large));
                                                    }
                                                    break;
                                            }
                                            DrawScreen();
                                        }
                                        break;
                                }
                            }
                        }
                        break;
                }
            }

        }

        /// <summary>
        /// reacts to the User double-clicking a region or button on the form
        /// </summary>
        private void FileDialog_GUI_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (bolIgnoreDoubleClick) return;
            bolIgnoreDoubleClick = true;
            if (cSweepPruneEle_UnderMouse != null)
            {
                enuSweepAndPruneObjectTypes eSWObjectType = (enuSweepAndPruneObjectTypes)cSweepPruneEle_UnderMouse.tag;
                switch (eSWObjectType)
                {
                    case enuSweepAndPruneObjectTypes.Region:
                        {
                            cRegionUnderMouse = (classRegion)cSweepPruneEle_UnderMouse.obj;
                            if (cRegionUnderMouse != null)
                            {
                                switch (cRegionUnderMouse.Region)
                                {
                                    case enuRegions.Title:
                                        {
                                        }
                                        break;

                                    case enuRegions.DirTree:
                                        {
                                            if (cRegionUnderMouse.cSweepAndPrune != null)
                                            {
                                                Point ptRegion = new Point(e.X - cRegionUnderMouse.rec.Left + cRegionUnderMouse.recVisible.Left,
                                                                           e.Y - cRegionUnderMouse.rec.Top + cRegionUnderMouse.recVisible.Top);
                                                classSweepAndPrune.classElement cEle_Button = cRegionUnderMouse.cSweepAndPrune.Search(ptRegion);
                                                if (cEle_Button != null)
                                                {
                                                    cBtnUnderMouse = (classButton)cEle_Button.obj;
                                                    cBtnUnderMouse.HighLight = true;
                                                    classTreeItem cTI_UnderMouse = (classTreeItem)cBtnUnderMouse.obj;
                                                    cRegionUnderMouse.Highlight = true;
                                                    switch (cBtnUnderMouse.eButtonType)
                                                    {
                                                        case classButton.enuButtonType.ExpandCollapse:
                                                            {
                                                            }
                                                            break;

                                                        case classButton.enuButtonType.Directory:
                                                            {
                                                                bolDrawScreen_Ignore = true;
                                                                cTICurrent = cTI_UnderMouse;
                                                                CurrentDirectory = cTI_UnderMouse.strPath;
                                                                cTICurrent.Expanded = !cTICurrent.Expanded;
                                                                bolDrawScreen_Ignore = false;
                                                                DrawScreen();
                                                            }
                                                            break;
                                                    }
                                                }
                                            }
                                        }
                                        break;

                                    case enuRegions.ContentCurrentDirectory:
                                        {
                                            if (cRegionUnderMouse.cSweepAndPrune != null)
                                            {
                                                Point ptRegion = new Point(e.X - cRegionUnderMouse.rec.Left + cRegionUnderMouse.recVisible.Left,
                                                                           e.Y - cRegionUnderMouse.rec.Top + cRegionUnderMouse.recVisible.Top);
                                                classSweepAndPrune.classElement cEle_Button = cRegionUnderMouse.cSweepAndPrune.Search(ptRegion);

                                                if (cEle_Button != null)
                                                {
                                                    cBtnUnderMouse = (classButton)cEle_Button.obj;
                                                    classTreeItem cTI_UnderMouse = (classTreeItem)cBtnUnderMouse.obj;
                                                    switch (cBtnUnderMouse.eButtonType)
                                                    {
                                                        case classButton.enuButtonType.File:
                                                            {
                                                                cBtnUnderMouse.Toggled = true;
                                                                if (cBtnUnderMouse.Toggled)
                                                                {
                                                                    cRegionUnderMouse.btnSelected = cBtnUnderMouse;
                                                                    for (int intCounter = 0; intCounter < lstButtonsSelected.Count; intCounter++)
                                                                        lstButtonsSelected[intCounter].Toggled = false;
                                                                    lstButtonsSelected.Clear();
                                                                    lstButtonsSelected.Add(cBtnUnderMouse);
                                                                    lstFiles.Clear();
                                                                    lstFiles.Add(((classTreeItem)cBtnUnderMouse.obj).strPath);
                                                                    confirm();
                                                                }
                                                            }
                                                            break;

                                                        case classButton.enuButtonType.Directory:
                                                            {
                                                                bolDrawScreen_Ignore = true;
                                                                cTICurrent = cTI_UnderMouse;
                                                                cTICurrent.Expanded = true;
                                                                regDirTree.IsRefreshed = false;
                                                                cDrawer_DirTree.Refreshed = false;
                                                                classTreeItem cTI_Parent = cTICurrent.Parent;
                                                                while (cTI_Parent != null)
                                                                {
                                                                    cTI_Parent.Expanded = true;
                                                                    cTI_Parent = cTI_Parent.Parent;
                                                                }
                                                                CurrentDirectory = cTI_UnderMouse.strPath;
                                                                bolDrawScreen_Ignore = false;
                                                            }
                                                            break;
                                                    }
                                                    DrawScreen();
                                                }
                                            }
                                        }
                                        break;

                                    case enuRegions.UserInput_Cancel:
                                        {
                                        }
                                        break;

                                    case enuRegions.UserInput_Confirm:
                                        {
                                        }
                                        break;

                                    case enuRegions.UserInput_TextInput:
                                        {
                                        }
                                        break;

                                    case enuRegions.Resize:
                                        {
                                        }
                                        break;
                                }
                            }
                        }
                        break;
                }

            }
            bolIgnoreDoubleClick = false;
        }

        /// <summary>
        /// repositions objects on the form when the form is designed by developer-code (not with Designer tool) and Resize region is not disabled
        /// </summary>
        private void FileDialog_GUI_SizeChanged(object sender, EventArgs e)
        {
            resize();
        }
        #endregion

        #region properties

        static int intIDCounter = 0;
        int intMyID = intIDCounter++;
        /// <summary>
        /// used for debugging perposes to Identify which GUI-FileDialog was active and being debugged
        /// </summary>
        public int ID { get { return intMyID; } }

        string strTitle = "Open File Dialog";
        /// <summary>
        /// text which appears in the Title Region
        /// </summary>
        public string Title
        {
            get { return strTitle; }
            set { strTitle = value; }
        }

        bool bolMultiSelect = false;
        /// <summary>
        /// when checked - allows the user to select multiple files that can be accessed with the FileNames property
        /// </summary>
        public bool MultiSelect
        {
            get { return bolMultiSelect; }
            set { bolMultiSelect = value; }
        }

        string strConfirm = "Confirm";
        /// <summary>
        /// text that appears on the UserInput_Confirm button 
        /// - by default 'Save' for SaveFileDialog & 'Load' for LoadFileDialog
        /// </summary>
        public string ConfirmText
        {
            get { return strConfirm; }
            set
            {
                strConfirm = value;
                regUserInput_Confirm.IsRefreshed = false;
            }
        }

        /// <summary>
        /// Text contained in the UserInput_TextInput Region
        /// </summary>
        public string UserInput_Text
        {
            get { return txtInput.Text; }
            set { txtInput.Text = value; }
        }

        /// <summary>
        /// current enuCursorState enumerated value of the Cursor 
        /// </summary>
        enuCursorState eCursorState
        {
            get { return _eCursorState; }
            set
            {
                if (_eCursorState != value)
                {
                    _eCursorState = value;
                    regUserInput_TextInput.Highlight = true;
                    DrawScreen();
                }
            }
        }

        /// <summary>
        /// list of file names selected
        /// </summary>
        public List<string> lstFiles = new List<string>();

        /// <summary>
        /// list of file names the User Selected before Confirm button was depressed when MultiSelect mode is enabled
        /// </summary>
        public string[] FileNames
        {
            get
            {
                Files_Set();
                if (lstFiles.Count < 2)
                {
                    lstFiles.Clear();

                    lstFiles.Add(txtInput.Tag != null
                                               ? (string)txtInput.Tag
                                               : txtInput.Text);
                }
                string[] cRetVal = lstFiles.ToArray();
                return cRetVal;
            }
        }

        /// <summary>
        /// single file selected by User when MultiSelect mode is disabled
        /// </summary>
        virtual public string FileName
        {
            get
            {
                if (lstFiles.Count > 0)
                    return lstFiles[0];
                else
                    return "";
            }
        }

        bool bolCanBeResized = false;
        /// <summary>
        /// allows the form to be resized by the User - default is false
        /// </summary>
        public bool CanBeResized
        {
            get { return bolCanBeResized; }
            set { bolCanBeResized = value; }
        }

        bool bolCanBeMoved = true;
        /// <summary>
        /// allows the form to be Moved when the User grabs the form's Title region - defeault is true
        /// </summary>
        public bool CanBeMoved
        {
            get { return bolCanBeMoved; }
            set { bolCanBeMoved = value; }
        }

        static string _CurrentDirectory = "";
        /// <summary>
        /// the full path of the Directory currently selected
        /// </summary>
        public string CurrentDirectory
        {
            get
            {
                if (_CurrentDirectory.Length == 0)
                {
                    CurrentDirectory = System.IO.Directory.GetCurrentDirectory();
                    BuildDirTree();
                }
                return _CurrentDirectory;
            }
            set
            {
                if (System.IO.Directory.Exists(value))
                {
                    regCurrentDirectory.IsRefreshed = false;

                    if (cTICurrent != null && cTICurrent.btn != null)
                        cTICurrent.btn.Toggled = false;

                    _CurrentDirectory = value;

                    try
                    {
                        txtInput.Text = value;
                        regDirTree.IsRefreshed = false;
                        cDrawer_DirTree.Refreshed = false;
                        DrawDirTree();

                        if (cTICurrent == null || cTICurrent.btn == null || cTICurrent.btn.ptDraw.Y < regDirTree.ptRecVisible_Offset.Y)
                        {
                            cTICurrent = TI_BinTree.Search(CurrentDirectory);
                            if (regDirTree.ScrollBarV_Shown)
                            {
                                if (regDirTree.cScrollBarV != null
                                    && cTICurrent != null
                                    && cTICurrent.btn != null)
                                {
                                    regDirTree.cScrollBarV.Value = (double)cTICurrent.btn.recArea.Top / (double)regDirTree.szBmp.Height;
                                }
                            }
                            if (cTICurrent != null && cTICurrent.btn != null)
                                cTICurrent.btn.Toggled = true;
                        }
                        resize();
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }

        /// <summary>
        /// the root element of the Directory Tree's binary-tree search engine - will typically reflect data for "c:\" directory
        /// </summary>
        public classTreeItem cDirTree_Root = null;

        classTreeItem _cTICurrent = null;
        /// <summary>
        /// the Directory Tree-Item (File or Folder) currently being viewed by the User
        /// </summary>
        public classTreeItem cTICurrent
        {
            get { return _cTICurrent; }
            set
            {
                if (_cTICurrent != value)
                {
                    _cTICurrent = value;
                    regContent.IsRefreshed = false;
                    DrawScreen();
                }
            }
        }

        EventHandler event_Cancel = null;
        /// <summary>
        /// event specified by the Developer to be triggered whenever the User presses the 'Cancel' button
        /// </summary>
        public EventHandler event_Cancel_click
        {
            get { return event_Cancel; }
            set { event_Cancel = value; }
        }

        EventHandler event_Confirm = null;
        /// <summary>
        /// event specified by the Developer to be triggered whenever the User presses the 'Confirm' button
        /// </summary>
        public EventHandler event_Confirm_click
        {
            get { return event_Confirm; }
            set { event_Confirm = value; }
        }

        classScrollBar _cScrollBarUnderMouse = null;
        /// <summary>
        /// reflects which, if any, scroll bar is under the mouse cursor
        /// </summary>
        classScrollBar cScrollBarUnderMouse
        {
            get { return _cScrollBarUnderMouse; }
            set
            {
                if (_cScrollBarUnderMouse != value)
                {
                    if (_cScrollBarUnderMouse != null)
                        _cScrollBarUnderMouse.Grab = false;
                    _cScrollBarUnderMouse = value;
                }
            }
        }

        /// <summary>
        /// reflects which, if any, button is under the mouser cursor
        /// </summary>
        public classButton cBtnUnderMouse
        {
            get { return _cBtnUnderMouse; }
            set
            {
                if (_cBtnUnderMouse != value)
                {
                    if (_cBtnUnderMouse != null)
                        _cBtnUnderMouse.HighLight = _cBtnUnderMouse.Toggled;
                    _cBtnUnderMouse = value;
                    if (_cBtnUnderMouse != null)
                        _cBtnUnderMouse.HighLight = _cBtnUnderMouse.Toggled;
                }
            }
        }

        string strFilter = "All files(*.*)|*.*";
        /// <summary>
        /// specifies the file filter for the FileDialog 
        ///     e.g. openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
        /// </summary>
        public string Filter
        {
            get { return strFilter; }
            set
            {
                strFilter = value;
                lstFilters = classFileFilterItem.Parse(strFilter);
                FilterIndex = 0;
            }
        }

        classRegion cRegionUnderMouse = null;
        /// <summary>
        /// points to the Region currently under the Mouse Cursor
        /// </summary>
        public classRegion RegionUnderMouse
        {
            get { return cRegionUnderMouse; }
        }

        bool bolOverrideConfirmCancel = false;
        /// <summary>
        /// when set - both Confirm & Cancel button pressing events
        /// used by the formFileDialog_Designer app to allow Developer to select 'Confirm' & 'Cancel' regions without destroying the GUI-FileDialog being designed
        /// </summary>
        public bool OverrideConfirmCancel
        {
            get { return bolOverrideConfirmCancel; }
            set { bolOverrideConfirmCancel = true; }
        }

        List<classFileFilterItem> lstFilters = new List<classFileFilterItem>();

        int intFilterIndex = 1;
        /// <summary>
        /// File-Filter specified by User using the mouse-wheel over the UserInput_Filter region
        /// </summary>
        public int FilterIndex
        {
            get { return intFilterIndex; }
            set
            {
                if (value < 1 || value > lstFilters.Count) return;

                intFilterIndex = value;
                regUserInput_FilterInput.IsRefreshed = false;
                regContent.IsRefreshed = false;
                DrawScreen();
            }
        }

        Image _imgBackGround = null;
        /// <summary>
        /// specifies the background image of the PerPixelAlhpa form
        /// </summary>
        public override Image BackgroundImage
        {
            get { return _imgBackGround; }
            set
            {
                _imgBackGround = value;
                DrawScreen();
            }
        }

        Color clrTransparent = Color.FromArgb(1, 2, 3);
        /// <summary>
        /// specifies which color in the BackGroundImage is made transparent
        /// </summary>
        public Color TransparentColor
        {
            get { return clrTransparent; }
            set { clrTransparent = value; }
        }

        #endregion

        #region Draw
        Bitmap _bmpScreen = null;
        /// <summary>
        /// appearance of the GUI-FIleDialog when it is drawn to the screen
        /// </summary>
        public Bitmap bmpScreen
        {
            get { return _bmpScreen; }
        }

        bool _bolDrawScreen_Ignore = false;
        /// <summary>
        /// prevents DrawScreen from being called during execution of DrawScreen
        /// </summary>
        public bool bolDrawScreen_Ignore
        {
            get { return _bolDrawScreen_Ignore; }
            set
            {
                _bolDrawScreen_Ignore = value;
            }
        }

        /// <summary>
        /// calls the DrawScreen(false) - and does not reposition the Directory Tree's scroll value
        /// </summary>
        public void DrawScreen() { DrawScreen(false); }

        /// <summary>
        /// draws the screen and sets the PerPixelAlpha form's appearance
        /// </summary>
        /// <param name="bolPositionDirTree"></param>
        public void DrawScreen(bool bolPositionDirTree)
        {
            if (!bolRegionsDefined
                || regDirTree.bmp == null
                || bolDrawScreen_Ignore) return;
            bolDrawScreen_Ignore = true;
            try
            {
                _bmpScreen = new Bitmap(Width, Height);

            }
            catch (Exception eScreen)
            {
                System.Diagnostics.Debug.Print("DrawScreen error eScreen:" + eScreen.Message);
            }

            using (Graphics g = Graphics.FromImage(_bmpScreen))
            {
                try
                {
                    if (BackgroundImage != null)
                    {
                        g.DrawImage(BackgroundImage, 0, 0, Width, Height);
                    }
                    else
                    {
                        g.FillRectangle(new SolidBrush(BackColor), 0, 0, Width, Height);
                        g.DrawRectangle(new Pen(ForeColor), 0, 0, Width - 1, Height - 1);
                    }

                }
                catch (Exception eBackgroundImage)
                {
                    System.Diagnostics.Debug.Print("DrawScreen error eBAckgroundImage:" + eBackgroundImage.Message);

                }

                // draw regions
                {
                    try
                    {    // drawTitle 
                        DrawTitle();
                        g.DrawImage(regTitle.bmp, regTitle.rec, regTitle.recVisible, GraphicsUnit.Pixel);

                        // draw Current Directory
                        DrawCurrentDirectory();
                        g.DrawImage(regCurrentDirectory.bmp, regCurrentDirectory.rec, regCurrentDirectory.recVisible, GraphicsUnit.Pixel);

                    }
                    catch (Exception eTitle)
                    {

                        System.Diagnostics.Debug.Print("DrawScreen error eTitle:" + eTitle.Message);
                    }

                    try
                    {
                        // draw Dir-Tree
                        {
                            
                            DrawDirTree();
                            Rectangle recVisible = new Rectangle(regDirTree.ptRecVisible_Offset.X,
                                                                 regDirTree.ptRecVisible_Offset.Y,
                                                                 regDirTree.recVisible.Width,
                                                                 regDirTree.recVisible.Height);
                            g.DrawImage(regDirTree.bmp, regDirTree.rec, recVisible, GraphicsUnit.Pixel);

                            if (bolPositionDirTree)
                            {
                                if (cTICurrent == null)
                                {
                                    if (TI_BinTree != null)
                                        cTICurrent = TI_BinTree.Search(CurrentDirectory);
                                }
                                if (cTICurrent != null && cTICurrent.btn != null && cTICurrent.btn.DirTreeState == classDraw_DirTree.untDirTreeButton_State_Counter)
                                {
                                    regDirTree.cScrollBarV.Value = (double)cTICurrent.btn.recArea.Top / (double)regDirTree.szBmp.Height;
                                }
                            }

                            if (regDirTree.ScrollBar_V)
                            {
                                Bitmap bmpScrollV = regDirTree.ScrollBar_V_Image;
                                if (bmpScrollV != null)
                                {
                                    Rectangle recSource = new Rectangle(0, 0, bmpScrollV.Width, bmpScrollV.Height);
                                    g.DrawImage(bmpScrollV, regDirTree.cScrollBarV.recArea, recSource, GraphicsUnit.Pixel);
                                }
                                else
                                    ;
                            }
                            if (regDirTree.ScrollBar_H)
                            {
                                Bitmap bmpScrollH = regDirTree.ScrollBar_H_Image;
                                if (bmpScrollH != null)
                                {
                                    Rectangle recSource = new Rectangle(0, 0, bmpScrollH.Width, bmpScrollH.Height);
                                    g.DrawImage(bmpScrollH, regDirTree.cScrollBarH.recArea, recSource, GraphicsUnit.Pixel);
                                }
                                else
                                    ;
                            }
                            if (regDirTree.DrawBorder)
                                g.DrawRectangle(regDirTree.pForeground, new Rectangle(regDirTree.rec.Left, regDirTree.rec.Top, regDirTree.rec.Width - 1, regDirTree.rec.Height - 1));

                        }
                    }
                    catch (Exception eDirTree)
                    {

                        System.Diagnostics.Debug.Print("DrawScreen error eDirTree:" + eDirTree.Message);
                    }
                }

                try
                {
                    // draw Content
                    {
                        DrawContent();
                        Rectangle recVisible = new Rectangle(regContent.ptRecVisible_Offset.X,
                                                             regContent.ptRecVisible_Offset.Y,
                                                             regContent.recVisible.Width,
                                                             regContent.recVisible.Height);
                        g.DrawImage(regContent.bmp, regContent.rec, recVisible, GraphicsUnit.Pixel);

                        if (regContent.ScrollBar_H)
                        {
                            Bitmap bmpScrollH = regContent.ScrollBar_H_Image;
                            if (bmpScrollH != null)
                            {
                                Rectangle recSource = new Rectangle(0, 0, bmpScrollH.Width, bmpScrollH.Height);
                                g.DrawImage(bmpScrollH, regContent.cScrollBarH.recArea, recSource, GraphicsUnit.Pixel);
                            }
                            else
                                ;
                        }
                        if (regContent.DrawBorder)
                        {
                            g.DrawRectangle(regContent.pForeground, new Rectangle(regContent.rec.Left, regContent.rec.Top, regContent.rec.Width - 1, regContent.rec.Height - 1));
                        }
                    }
                }
                catch (Exception eDrawContent)
                {

                    System.Diagnostics.Debug.Print("DrawScreen error eDrawContent:" + eDrawContent.Message);
                }

                // draw user-input
                {
                    try
                    {  // draw label
                        {
                            drawUserInput_Label();
                            g.DrawImage(regUserInput_Label.bmp, regUserInput_Label.rec.Location);
                        }

                    }
                    catch (Exception eDrawLabel)
                    {

                        System.Diagnostics.Debug.Print("DrawScreen error eDrawLabel:" + eDrawLabel.Message);
                    }
                    try
                    {
                        // draw Confirm
                        {
                            drawUserInput_Confirm();
                            g.DrawImage(regUserInput_Confirm.bmp, regUserInput_Confirm.rec.Location);
                            if (regUserInput_Confirm.DrawBorder)
                                g.DrawRectangle(regUserInput_Confirm.pForeground,
                                                new Rectangle(regUserInput_Confirm.rec.Left,
                                                              regUserInput_Confirm.rec.Top,
                                                              regUserInput_Confirm.rec.Width - 1,
                                                              regUserInput_Confirm.rec.Height - 1));
                        }

                    }
                    catch (Exception eConfirm)
                    {
                        System.Diagnostics.Debug.Print("DrawScreen error eConfirm:" + eConfirm.Message);
                    }
                    try
                    {
                        // draw Cancel
                        {
                            drawUserInput_Cancel();
                            g.DrawImage(regUserInput_Cancel.bmp, regUserInput_Cancel.rec.Location);
                            if (regUserInput_Cancel.DrawBorder)
                                g.DrawRectangle(regUserInput_Cancel.pForeground,
                                                new Rectangle(regUserInput_Cancel.rec.Left,
                                                              regUserInput_Cancel.rec.Top,
                                                              regUserInput_Cancel.rec.Width - 1,
                                                              regUserInput_Cancel.rec.Height - 1));
                        }

                    }
                    catch (Exception eCancel)
                    {
                        System.Diagnostics.Debug.Print("DrawScreen error eCancel:" + eCancel.Message);
                    }

                    try
                    {
                        // draw Filter-Input
                        {
                            drawUserInput_FilterInput();
                            Rectangle recSource = regUserInput_FilterInput.recVisible;
                            Rectangle recDest = new Rectangle(regUserInput_FilterInput.rec.Location, regUserInput_FilterInput.recVisible.Size);
                            g.DrawImage(regUserInput_FilterInput.bmp, recDest, recSource, GraphicsUnit.Pixel);
                            if (regUserInput_FilterInput.DrawBorder)
                                g.DrawRectangle(regUserInput_FilterInput.pForeground, regUserInput_FilterInput.rec.Left, regUserInput_FilterInput.rec.Top, regUserInput_FilterInput.recVisible.Size.Width - 2, regUserInput_FilterInput.recVisible.Size.Height - 2);
                        }

                    }
                    catch (Exception eFilterInput)
                    {

                        System.Diagnostics.Debug.Print("DrawScreen error eFilterInput:" + eFilterInput.Message);
                    }
                    try
                    {
                        // draw Text-Input
                        {
                            drawUserInput_TextInput();
                            Rectangle recSource = regUserInput_TextInput.recVisible;
                            Rectangle recDest = new Rectangle(regUserInput_TextInput.rec.Location, regUserInput_TextInput.recVisible.Size);
                            g.DrawImage(regUserInput_TextInput.bmp, recDest, recSource, GraphicsUnit.Pixel);
                            if (regUserInput_TextInput.DrawBorder)
                                g.DrawRectangle(regUserInput_TextInput.pForeground, regUserInput_TextInput.rec.Left, regUserInput_TextInput.rec.Top, regUserInput_TextInput.bmp.Width - 2, regUserInput_TextInput.bmp.Height - 2);
                        }
                    }
                    catch (Exception eTextInput)
                    {
                        System.Diagnostics.Debug.Print("DrawScreen error eTextInput:" + eTextInput.Message);
                    }
                    try
                    {
                        // drawResize 
                        if (CanBeResized)
                        {
                            DrawResize();
                            g.DrawImage(regResize.bmp, regResize.rec, regResize.recVisible, GraphicsUnit.Pixel);
                        }
                    }
                    catch (Exception eResize)
                    {
                        System.Diagnostics.Debug.Print("DrawScreen error eResize:" + eResize.Message);
                    }
                }
            }
            _bmpScreen.MakeTransparent(clrTransparent);
            byte bytOpacity = (byte)(((int)(Opacity * 255.0)) % 256);
            SetBitmap(_bmpScreen, bytOpacity);
            bolDrawScreen_Ignore = false;
        }

        /// <summary>
        /// pointer to the class that draws the UserInput buttons Confirm & Cancel
        /// </summary>
        public classDraw_UserInput_Button cUserInputButtonDrawer = null;

        /// <summary>
        /// pointer to the class that draws the Directory Tree
        /// </summary>
        public classDraw_DirTree cDrawer_DirTree = null;

        /// <summary>
        /// sets content of and draws the current state of the Directory Tree with the classDraw_DirTree class
        /// </summary>
        void DrawDirTree()
        {
            cDrawer_DirTree.Draw(ref cDirTree_Root);
            if (regDirTree.BlendBackground)
                regDirTree.bmp.MakeTransparent(regDirTree.brBackground.Color);
        }

        /// <summary>
        /// draws the UserInput_FilterInput region
        /// </summary>
        void drawUserInput_FilterInput()
        {
            if (regUserInput_FilterInput.IsRefreshed && !regUserInput_FilterInput.Highlight) return;

            if (!regUserInput_FilterInput.IsRefreshed)
            {
                string strText = lstFilters.Count > 0
                                                  ? lstFilters[FilterIndex - 1].Label
                                                  : "All files";
                Size szText = TextRenderer.MeasureText(strText, regUserInput_FilterInput.font);
                szText.Width += 20;
                if (szText.Width < regUserInput_FilterInput.rec.Width)
                    szText.Width = regUserInput_FilterInput.rec.Width;
                if (szText.Height < regUserInput_FilterInput.rec.Height)
                    szText.Height = regUserInput_FilterInput.rec.Height;
                regUserInput_FilterInput.bmp = new Bitmap(szText.Width, szText.Height);

                using (Graphics g = Graphics.FromImage(regUserInput_FilterInput.bmp))
                {
                    g.FillRectangle(regUserInput_FilterInput.brBackground, 0, 0, regUserInput_FilterInput.bmp.Width, regUserInput_FilterInput.bmp.Height);
                    g.DrawString(strText, regUserInput_FilterInput.font, regUserInput_FilterInput.brForeground, new Point(2, (regUserInput_FilterInput.bmp.Height - szText.Height) / 2));
                }

                if (regUserInput_FilterInput.BlendBackground)
                    regUserInput_FilterInput.bmp.MakeTransparent(regUserInput_FilterInput.brBackground.Color);
            }

            regUserInput_FilterInput.IsRefreshed = true;
        }

        /// <summary>
        /// draws the UserInput_TextInput region
        /// </summary>
        void drawUserInput_TextInput()
        {
            if (regUserInput_TextInput.IsRefreshed && !regUserInput_TextInput.Highlight) return;

            if (!regUserInput_TextInput.IsRefreshed)
            { // rebuild bitmap, SweepAndPrune and buttons
                Size szText = TextRenderer.MeasureText(UserInput_Text, regUserInput_TextInput.font);
                szText.Width += 20;
                if (szText.Width < regUserInput_TextInput.rec.Width)
                    szText.Width = regUserInput_TextInput.rec.Width;
                if (szText.Height < regUserInput_TextInput.rec.Height)
                    szText.Height = regUserInput_TextInput.rec.Height;
                regUserInput_TextInput.bmp = new Bitmap(szText.Width, szText.Height);

                using (Graphics g = Graphics.FromImage(regUserInput_TextInput.bmp))
                {
                    g.FillRectangle(regUserInput_TextInput.brBackground, 0, 0, regUserInput_TextInput.bmp.Width, regUserInput_TextInput.bmp.Height);
                    regUserInput_TextInput.cSweepAndPrune.lstElements.Clear();
                    Point pt = new Point(1, 1);
                    Point ptCursor = new Point(-1, -1);
                    for (int intCharCounter = 0; intCharCounter < txtInput.Text.Length; intCharCounter++)
                    {
                        classSweepAndPrune.classElement cSWEle = new classSweepAndPrune.classElement();
                        regUserInput_TextInput.cSweepAndPrune.Add(ref cSWEle);

                        char chr = txtInput.Text[intCharCounter];
                        classButton cBtn = new classButton();
                        cSWEle.obj = (object)cBtn;

                        classCharImage cCharImage = classCharImage.get(chr);
                        cBtn.bmp = cCharImage.bmp;
                        cBtn.bmpHighlight = cCharImage.bmpHighlight;

                        cBtn.recArea.Location
                            = cSWEle.rec.Location = pt;
                        cBtn.recArea.Size
                            = cSWEle.rec.Size = cBtn.bmp.Size;
                        cBtn.cParentRegion = regUserInput_TextInput;
                        bool bolHighlight = (txtInput.SelectionStart >= 0
                                                && intCharCounter > txtInput.SelectionStart
                                                && intCharCounter < txtInput.SelectionStart + txtInput.SelectionLength);
                        g.DrawImage(bolHighlight ? cBtn.bmpHighlight : cBtn.bmp, pt);

                        pt.X += cBtn.bmp.Width;
                    }
                }
            }

            // redraw buttons that need to be refreshed
            using (Graphics g = Graphics.FromImage(regUserInput_TextInput.bmp))
            {
                string strHighlight = txtInput.SelectionStart.ToString() + ":" + txtInput.SelectionLength.ToString() + "\r\n";
                for (int intCounter = 0; intCounter < regUserInput_TextInput.cSweepAndPrune.lstElements.Count; intCounter++)
                {
                    classButton cBtn = (classButton)regUserInput_TextInput.cSweepAndPrune.lstElements[intCounter].obj;
                    bool bolHighlight = intCounter >= txtInput.SelectionStart && intCounter < txtInput.SelectionStart + txtInput.SelectionLength;
                    cBtn.Refreshed = (bolHighlight == cBtn.HighLight);
                    cBtn.HighLight = bolHighlight;

                    strHighlight += cBtn.HighLight ? "1" : "0";

                    if (!cBtn.Refreshed)
                        g.DrawImage(cBtn.HighLight ? cBtn.bmpHighlight : cBtn.bmp, cBtn.recArea.Location);
                }

                if (eCursorState == enuCursorState.Blink_On && regUserInput_TextInput.cSweepAndPrune.lstElements.Count >= txtInput.SelectionStart)
                {
                    Point ptCursor_Top = new Point();
                    classButton cBtnCursor = null;
                    if (regUserInput_TextInput.cSweepAndPrune.lstElements.Count > txtInput.SelectionStart)
                    {
                        cBtnCursor = (classButton)regUserInput_TextInput.cSweepAndPrune.lstElements[txtInput.SelectionStart].obj;
                        ptCursor_Top = new Point(cBtnCursor.recArea.Location.X + 2, cBtnCursor.recArea.Location.Y);
                        Point ptCursor_Bottom = new Point(ptCursor_Top.X, cBtnCursor.recArea.Bottom);
                        g.DrawLine(new Pen(regUserInput_TextInput.brForeground.Color, 2), ptCursor_Top, ptCursor_Bottom);
                    }
                    else if (regUserInput_TextInput.cSweepAndPrune.lstElements.Count > 0)
                    {
                        cBtnCursor = (classButton)regUserInput_TextInput.cSweepAndPrune.lstElements[regUserInput_TextInput.cSweepAndPrune.lstElements.Count - 1].obj;
                        ptCursor_Top = new Point(cBtnCursor.recArea.Right, cBtnCursor.recArea.Top);
                        Point ptCursor_Bottom = new Point(ptCursor_Top.X, cBtnCursor.recArea.Bottom);
                        g.DrawLine(new Pen(regUserInput_TextInput.brForeground.Color, 2), ptCursor_Top, ptCursor_Bottom);
                    }
                    else
                    {
                        ptCursor_Top = new Point(3, 0);
                        Point ptCursor_Bottom = new Point(ptCursor_Top.X, regUserInput_TextInput.bmp.Height);
                        g.DrawLine(new Pen(regUserInput_TextInput.brForeground.Color, 2), ptCursor_Top, ptCursor_Bottom);
                    }
                }
            }

            if (regUserInput_TextInput.BlendBackground)
                regUserInput_TextInput.bmp.MakeTransparent(regUserInput_TextInput.brBackground.Color);

            regUserInput_TextInput.IsRefreshed = true;
            regUserInput_TextInput.Highlight = false;
        }

        /// <summary>
        /// draws the UserInput_Label region
        /// </summary>
        void drawUserInput_Label()
        {
            if (regUserInput_Label.IsRefreshed) return;
            regUserInput_Label.bmp = new Bitmap(regUserInput_Label.rec.Width, regUserInput_Label.rec.Height);
            string strText = "File";
            using (Graphics g = Graphics.FromImage(regUserInput_Label.bmp))
            {
                g.FillRectangle(regUserInput_Label.brBackground, new RectangleF(0, 0, regUserInput_Label.bmp.Width, regUserInput_Label.bmp.Height));
                if (regUserInput_Label.DrawBorder)
                    g.DrawRectangle(regUserInput_Label.pForeground, new Rectangle(0, 0, regUserInput_Label.bmp.Width - 1, regUserInput_Label.bmp.Height - 1));
                Size szText = TextRenderer.MeasureText(strText, regUserInput_Label.font);
                Point ptLocation = new Point(0,
                                             (regUserInput_Label.bmp.Height - szText.Height) / 2);
                g.DrawString(strText,
                             regUserInput_Label.font,
                             regUserInput_Label.brForeground,
                             ptLocation);
            }
            if (regUserInput_Label.BlendBackground)
                regUserInput_Label.bmp.MakeTransparent(regUserInput_Label.brBackground.Color);

            regUserInput_Label.IsRefreshed = true;
        }

        /// <summary>
        /// draws the UserInput_cancel region
        /// </summary>
        void drawUserInput_Cancel()
        {
            if (regUserInput_Cancel.IsRefreshed && !regUserInput_Cancel.Highlight) return;

            regUserInput_Cancel.bmp = new Bitmap(regUserInput_Cancel.rec.Width, regUserInput_Cancel.rec.Height);
            string strText = "Cancel";
            Size szText = TextRenderer.MeasureText(strText, regUserInput_Cancel.font);
            Point ptLocation = new Point((regUserInput_Cancel.bmp.Width - szText.Width) / 2,
                                         (regUserInput_Cancel.bmp.Height - szText.Height) / 2);

            if (regUserInput_Cancel.cSweepAndPrune.lstElements.Count == 0)
            {
                regUserInput_Cancel.cSweepAndPrune.lstElements.Clear();

                classButton cBtn = new classButton();
                cBtn.Text = strText;
                cBtn.cParentRegion = regUserInput_Cancel;
                cBtn.recArea = new Rectangle(0, 0, regUserInput_Cancel.rec.Width, regUserInput_Cancel.rec.Height);

                classSweepAndPrune.classElement cEle = new classSweepAndPrune.classElement();
                cEle.rec = cBtn.recArea;
                cEle.obj = (object)cBtn;
                cEle.tag = (object)classButton.enuButtonType.UserInput;

                regUserInput_Cancel.cSweepAndPrune.Add(ref cEle);
                cUserInputButtonDrawer.Draw(ref cBtn);
            }
            classButton cBtnCancel = (classButton)regUserInput_Cancel.cSweepAndPrune.lstElements[0].obj;
            using (Graphics g = Graphics.FromImage(regUserInput_Cancel.bmp))
            {
                g.FillRectangle(regUserInput_Cancel.brBackground, 0, 0, regUserInput_Cancel.bmp.Width, regUserInput_Cancel.rec.Height);
                g.DrawImage(cBtnCancel.HighLight ? cBtnCancel.bmpHighlight : cBtnCancel.bmp, 0, 0);


            }
            if (regUserInput_Cancel.BlendBackground)
                regUserInput_Cancel.bmp.MakeTransparent(regUserInput_Cancel.brBackground.Color);
            regUserInput_Cancel.IsRefreshed = true;
        }

        /// <summary>
        /// draws the UserInput_Confirm region
        /// </summary>
        void drawUserInput_Confirm()
        {
            if (regUserInput_Confirm.IsRefreshed && !regUserInput_Confirm.Highlight) return;

            regUserInput_Confirm.bmp = new Bitmap(regUserInput_Confirm.rec.Width, regUserInput_Confirm.rec.Height);
            string strText = ConfirmText; //"Confirm";
            Size szText = TextRenderer.MeasureText(strText, regUserInput_Confirm.font);
            Point ptLocation = new Point((regUserInput_Confirm.bmp.Width - szText.Width) / 2,
                                         (regUserInput_Confirm.bmp.Height - szText.Height) / 2);

            if (regUserInput_Confirm.cSweepAndPrune.lstElements.Count == 0)
            {
                regUserInput_Confirm.cSweepAndPrune.lstElements.Clear();

                classButton cBtn = new classButton();
                cBtn.Text = strText;
                cBtn.cParentRegion = regUserInput_Confirm;
                cBtn.recArea = new Rectangle(0, 0, regUserInput_Confirm.rec.Width, regUserInput_Confirm.rec.Height);

                classSweepAndPrune.classElement cEle = new classSweepAndPrune.classElement();
                cEle.rec = cBtn.recArea;
                cEle.obj = (object)cBtn;
                cEle.tag = (object)classButton.enuButtonType.UserInput;

                regUserInput_Confirm.cSweepAndPrune.Add(ref cEle);
                cUserInputButtonDrawer.Draw(ref cBtn);
            }
            classButton cBtnConfirm = (classButton)regUserInput_Confirm.cSweepAndPrune.lstElements[0].obj;
            using (Graphics g = Graphics.FromImage(regUserInput_Confirm.bmp))
            {
                g.FillRectangle(regUserInput_Confirm.brBackground, 0, 0, regUserInput_Confirm.bmp.Width, regUserInput_Confirm.rec.Height);
                g.DrawImage(cBtnConfirm.HighLight ? cBtnConfirm.bmpHighlight : cBtnConfirm.bmp, 0, 0);
            }
            if (regUserInput_Confirm.BlendBackground)
                regUserInput_Confirm.bmp.MakeTransparent(regUserInput_Confirm.brBackground.Color);
            regUserInput_Confirm.IsRefreshed = true;
        }

        /// <summary>
        /// pointer to instance of the classDraw_Content CurrentDirectoryContent region drawing class
        /// </summary>
        public classDraw_Content cDrawer_Content = null;

        /// <summary>
        /// draws the CurrentDirectoryContent region
        /// </summary>
        void DrawContent()
        {
            cDrawer_Content.Draw();
            if (regContent.BlendBackground)
                regContent.bmp.MakeTransparent(regContent.brBackground.Color);
        }

        /// <summary>
        /// draws the CurrentDirectory region
        /// </summary>
        void DrawCurrentDirectory()
        {
            if (regCurrentDirectory.IsRefreshed
                || regCurrentDirectory.rec.Height < szMin.Height
                || regCurrentDirectory.rec.Width < szMin.Width) return;

            regCurrentDirectory.bmp = new Bitmap(regCurrentDirectory.rec.Width - 2, regCurrentDirectory.rec.Height - 2);

            using (Graphics g = Graphics.FromImage(regCurrentDirectory.bmp))
            {
                g.FillRectangle(new SolidBrush(regCurrentDirectory.ColorBackground), 0, 0, regCurrentDirectory.bmp.Width, regCurrentDirectory.bmp.Height);
                if (regCurrentDirectory.DrawBorder)
                    g.DrawRectangle(new Pen(regCurrentDirectory.ColorForeground), 1, 1, regCurrentDirectory.bmp.Width - 2, regCurrentDirectory.bmp.Height - 2);
                Size szText = TextRenderer.MeasureText(CurrentDirectory, regCurrentDirectory.font);
                g.DrawString(CurrentDirectory, regCurrentDirectory.font, new SolidBrush(regCurrentDirectory.ColorForeground), new Point(2, (regCurrentDirectory.rec.Height - szText.Height) / 2));
            }
            if (regCurrentDirectory.BlendBackground)
                regCurrentDirectory.bmp.MakeTransparent(regCurrentDirectory.brBackground.Color);

            regCurrentDirectory.IsRefreshed = true;
        }

        /// <summary>
        /// draws the Title region
        /// </summary>
        void DrawTitle()
        {
            if (regTitle.IsRefreshed
                || regTitle.rec.Height < szMin.Height
                || regTitle.rec.Width < szMin.Width) return;

            regTitle.bmp = new Bitmap(regTitle.size.Width - 2, regTitle.size.Height - 2);
            using (Graphics g = Graphics.FromImage(regTitle.bmp))
            {
                g.FillRectangle(new SolidBrush(regTitle.ColorBackground), 0, 0, regTitle.bmp.Width, regTitle.bmp.Height);
                Size szText = TextRenderer.MeasureText(Title, regTitle.font);
                g.DrawString(Title, regTitle.font, new SolidBrush(regTitle.ColorForeground), new Point(3, (regTitle.bmp.Height - szText.Height) / 2));
                if (regTitle.DrawBorder)
                    g.DrawRectangle(new Pen(regTitle.ColorForeground), 1, 1, regTitle.bmp.Width - 2, regTitle.bmp.Height - 2);
            }
            if (regTitle.BlendBackground)
                regTitle.bmp.MakeTransparent(regTitle.brBackground.Color);

            regTitle.IsRefreshed = true;
        }

        /// <summary>
        /// draws the Resize region when the CanBeResized property to true
        /// </summary>
        void DrawResize()
        {
            if (regResize.IsRefreshed
                || regResize.rec.Width < szMin.Width
                || regResize.rec.Height < szMin.Height) return;



            regResize.bmp = new Bitmap(regResize.IsFixedWidth
                                           ? regResize.size.Width
                                           : regResize.recVisible.Width,
                                       regResize.IsFixedHeight
                                           ? regResize.size.Height
                                           : regResize.recVisible.Height);
            Pen pForeground = new Pen(regResize.ColorForeground);

            using (Graphics g = Graphics.FromImage(regResize.bmp))
            {
                g.FillRectangle(new SolidBrush(regResize.ColorBackground), 0, 0, regResize.bmp.Width, regResize.bmp.Height);

                Point ptBR = new Point(regResize.bmp.Width - 2, regResize.bmp.Height - 2);
                int intArrowWidth = 2;
                g.DrawLine(pForeground, 1, 1, ptBR.X, ptBR.Y);
                g.DrawLine(pForeground, 1, intArrowWidth, 1, 4);
                g.DrawLine(pForeground, intArrowWidth, 1, 4, 1);
                g.DrawLine(pForeground, ptBR.X, ptBR.Y, ptBR.X - intArrowWidth, ptBR.Y);
                g.DrawLine(pForeground, ptBR.X, ptBR.Y, ptBR.X, ptBR.Y - intArrowWidth);
            }


            if (regResize.BlendBackground)
                regResize.bmp.MakeTransparent(regResize.brBackground.Color);

            regResize.IsRefreshed = true;
        }


        #endregion

        #region BuildDirTree
        /// <summary>
        /// builds the directory tree by stepping backwards from current directory to Root directory then branching forward through all Expanded Sub-directories
        /// </summary>
        void BuildDirTree()
        {
            if (System.IO.Directory.Exists(CurrentDirectory))
            {
                FileDialog_GUI cMyRef = this;
                cTICurrent = classTreeItem.New(ref cMyRef, CurrentDirectory);

                int intIndexLastBackSlash = CurrentDirectory.LastIndexOf('\\');
                if (intIndexLastBackSlash >= 0)
                {
                    cTICurrent.eTreeItemType = classTreeItem.enuTreeItemType.directory;
                    cTICurrent.strName = CurrentDirectory.Substring(intIndexLastBackSlash + 1);
                    cTICurrent.strPath = CurrentDirectory;
                    cTICurrent.setDirContents();
                    cTICurrent.Expanded = true;

                    // recurse backwards until find Root
                    classTreeItem cTI_Ref = cTICurrent;
                    BuildTree_Recurse(ref cTI_Ref);
                }

                BuildTree_SetNumParents(ref cDirTree_Root);
            }
        }

        /// <summary>
        /// counts a Directory Tree Item's parents to determine its tab location in the Directory Tree Region
        /// </summary>
        /// <param name="cTI"></param>
        void BuildTree_SetNumParents(ref classTreeItem cTI)
        {
            if (cTI == null) return;
            if (cTI.Expanded && cTI.lstContent == null)
                cTI.setDirContents();
            for (int intCounter = 0; cTI.lstContent != null && intCounter < cTI.lstContent.Count; intCounter++)
            {
                classTreeItem cTI_Sub = cTI.lstContent[intCounter];
                cTI_Sub.intNumParents = cTI.intNumParents + 1;
                BuildTree_SetNumParents(ref cTI_Sub);
            }
        }

        /// <summary>
        /// inserts the reference input paramenter Tree-Item into the DirectoryTree's BinaryTree search engine
        /// then recurses backwards through its ancestors to the current drive's root 
        /// expanding the parent's Directory and loading their contents (files & sub-dirs)
        /// </summary>
        /// <param name="cTI"></param>
        void BuildTree_Recurse(ref classTreeItem cTI)
        {
            TI_BinTree.Insert(ref cTI);
            string strPath = cTI.strPath.Substring(0, cTI.strPath.Length - cTI.strName.Length - 1);
            FileDialog_GUI cMyRef = this;
            classTreeItem cTI_Parent = classTreeItem.New(ref cMyRef, strPath);

            int intIndexLastBackSlash = cTI_Parent.strPath.LastIndexOf('\\');
            if (intIndexLastBackSlash >= 0)
            {
                cTI_Parent.strName = cTI_Parent.strPath.Substring(intIndexLastBackSlash + 1);
                cTI_Parent.eTreeItemType = classTreeItem.enuTreeItemType.directory;

                if (System.IO.Directory.Exists(cTI_Parent.strPath))
                {
                    cTI_Parent.setDirContents(ref cTI);
                    cTI_Parent.Expanded = true;

                    if (cTI_Parent.strPath.Length > "c:\\".Length)
                        BuildTree_Recurse(ref cTI_Parent);
                }
            }
            else
            {
                cDirTree_Root = cTI_Parent;
                cDirTree_Root.strName = cDirTree_Root.strPath;
                cDirTree_Root.strPath += '\\';
                cDirTree_Root.setDirContents(ref cTI);
                cDirTree_Root.eTreeItemType = classTreeItem.enuTreeItemType.directory;
                cDirTree_Root.Expanded = true;
                TI_BinTree.Insert(ref cDirTree_Root);
            }
        }
        #endregion

        /// <summary>
        /// clears the lstFiles files List and adds all files that the User has currently selected
        /// </summary>
        void Files_Set()
        {
            lstFiles.Clear();
            for (int intCounter = 0; intCounter < regContent.cSweepAndPrune.lstElements.Count; intCounter++)
            {
                classSweepAndPrune.classElement cSPEle = regContent.cSweepAndPrune.lstElements[intCounter];
                classButton cBtn = (classButton)cSPEle.obj;
                if (cBtn.Toggled)
                {
                    classTreeItem cTI = (classTreeItem)cBtn.obj;
                    lstFiles.Add(cTI.strPath);
                }
            }
        }

        /// <summary>
        /// points to the SweepAndPrune Element under the mouse (region or scroll bar)
        /// </summary>
        classSweepAndPrune.classElement cSweepPruneEle_UnderMouse = null;

        /// <summary>
        /// points to the button under the mouse
        /// </summary>
        classButton _cBtnUnderMouse = null;

        /// <summary>
        /// contains list of buttons currently selected by the User
        /// </summary>
        List<classButton> lstButtonsSelected = new List<classButton>();

        /// <summary>
        /// returns the smallest rectangle that contains two points
        /// </summary>
        /// <param name="pt1">first of two points contained in requested rectangle</param>
        /// <param name="pt2">second of two points contained in requested rectangle</param>
        /// <returns></returns>
        public static Rectangle RectangleFromTwoPoints(Point pt1, Point pt2)
        {
            return new Rectangle(pt1.X <= pt2.X ? pt1.X : pt2.X,
                                 pt1.Y <= pt2.Y ? pt1.Y : pt2.Y,
                                (int)Math.Abs(pt1.X - pt2.X),
                                (int)Math.Abs(pt1.Y - pt2.Y));

        }

        /// <summary>
        /// used to control double-click event
        /// </summary>
        bool bolIgnoreDoubleClick = false;


        /// <summary>
        /// repositions regions and scroll bars in the form's SweepAndClean algorithm
        /// </summary>
        public void resize()
        {
            if (!bolActivated) return;
            cSweepAndPrune.lstElements.Clear();
            for (int intRegionCounter = 0; intRegionCounter < lstRegions.Count; intRegionCounter++)
            {
                classRegion cRegion = lstRegions[intRegionCounter];

                cRegion.ParentSizeChanged();
                //                  define region in Sweep And Prune
                {
                    //          define size of H scrollbar
                    {
                        cRegion.cScrollBarH.recArea = new Rectangle(cRegion.rec.Left,
                                                                cRegion.rec.Bottom - cRegion.ScrollBarWidth,
                                                                cRegion.rec.Width - (cRegion.ScrollBar_V ? cRegion.ScrollBarWidth : 0),
                                                                cRegion.ScrollBarWidth);
                        if (cRegion.cScrollBarH.recArea.Width < 1)
                            cRegion.cScrollBarH.recArea = new Rectangle(cRegion.cScrollBarH.recArea.Location, new Size(1, cRegion.cScrollBarH.recArea.Size.Height));
                        if (cRegion.cScrollBarH.recArea.Height < 1)
                            cRegion.cScrollBarH.recArea = new Rectangle(cRegion.cScrollBarH.recArea.Location, new Size(cRegion.cScrollBarH.recArea.Size.Width, 1));

                        if (cRegion.ScrollBar_H)
                        {
                            classSweepAndPrune.classElement cEle_Scroll_H = new classSweepAndPrune.classElement();
                            object objRegion_Scroll_H = (object)cRegion.cScrollBarH;
                            cEle_Scroll_H.obj = objRegion_Scroll_H;
                            cEle_Scroll_H.rec = cRegion.cScrollBarH.recArea;
                            cEle_Scroll_H.tag = (object)enuSweepAndPruneObjectTypes.ScrollBar;
                            cSweepAndPrune.Add(ref cEle_Scroll_H);
                        }
                    }

                    // define Size of V scrollBar
                    {
                        cRegion.cScrollBarV.recArea = new Rectangle(cRegion.rec.Right - cRegion.ScrollBarWidth,
                                                                cRegion.rec.Top,
                                                                cRegion.ScrollBarWidth,
                                                                cRegion.rec.Height - (cRegion.ScrollBar_H ? cRegion.ScrollBarWidth : 0));
                        if (cRegion.cScrollBarV.recArea.Width < 1)
                            cRegion.cScrollBarV.recArea = new Rectangle(cRegion.cScrollBarV.recArea.Location, new Size(1, cRegion.cScrollBarV.recArea.Size.Height));
                        if (cRegion.cScrollBarV.recArea.Height < 1)
                            cRegion.cScrollBarV.recArea = new Rectangle(cRegion.cScrollBarV.recArea.Location, new Size(cRegion.cScrollBarV.recArea.Size.Width, 1));

                        if (cRegion.ScrollBar_V)
                        {
                            classSweepAndPrune.classElement cEle_Scroll_V = new classSweepAndPrune.classElement();
                            object objRegion_Scroll_V = (object)cRegion.cScrollBarV;
                            cEle_Scroll_V.obj = objRegion_Scroll_V;
                            cEle_Scroll_V.rec = cRegion.cScrollBarV.recArea;
                            cEle_Scroll_V.tag = (object)enuSweepAndPruneObjectTypes.ScrollBar;
                            cSweepAndPrune.Add(ref cEle_Scroll_V);
                        }
                    }

                    classSweepAndPrune.classElement cEle = new classSweepAndPrune.classElement();
                    object objRegion = (object)cRegion;
                    cEle.obj = objRegion;
                    cEle.rec = new Rectangle(cRegion.rec.Left,
                                             cRegion.rec.Top,
                                             cRegion.rec.Width - (cRegion.ScrollBar_V ? cRegion.cScrollBarV.bmp.Width : 0),
                                             cRegion.rec.Height - (cRegion.ScrollBar_H ? cRegion.cScrollBarH.bmp.Height : 0));
                    cEle.tag = (object)enuSweepAndPruneObjectTypes.Region;
                    cSweepAndPrune.Add(ref cEle);
                }
            }
        }

        /// <summary>
        /// returns the File SearchPattern used when determinine what files the User wants visible in the CurrentDirectoryContents region
        /// the return value reflects both the File-Filter selected and the contents of the UserInput_TextInput textbox
        /// </summary>
        public List<string> SearchPattern
        {
            get
            {
                List<string> lstRetVal = new List<string>();
                if (lstFilters.Count >= intFilterIndex && intFilterIndex > 0)
                {
                    char[] chrSplit = { ';' };
                    string strFilename_Partial = "";
                    if (cTICurrent != null)
                    {
                        lstRetVal.AddRange(lstFilters[intFilterIndex - 1].SearchPattern.Split(chrSplit).ToList<string>());
                        if (string.Compare(cTICurrent.strPath.ToUpper().Trim(), txtInput.Text.ToUpper().Trim()) != 0)
                        {
                            if (txtInput.Text.Trim().Length > cTICurrent.strPath.Length && string.Compare(txtInput.Text.Substring(0, cTICurrent.strPath.Length).ToUpper(), cTICurrent.strPath.ToUpper()) == 0)
                            {
                                strFilename_Partial = txtInput.Text.Substring(cTICurrent.strPath.Length);
                                while (strFilename_Partial.Length > 0 && strFilename_Partial[0] == '\\')
                                    strFilename_Partial = strFilename_Partial.Substring(1);
                            }
                            else
                            {
                                int intLastDecimal = txtInput.Text.LastIndexOf('.');
                                if (intLastDecimal >= 0)
                                {
                                    lstRetVal.Clear();
                                    lstRetVal.Add(txtInput.Text);
                                    return lstRetVal;
                                }
                                else
                                    strFilename_Partial = txtInput.Text;
                            }
                        }
                    }

                    while (lstRetVal.Contains(""))
                        lstRetVal.Remove("");
                    strFilename_Partial = strFilename_Partial.Trim();
                    for (int intCounter = 0; intCounter < lstRetVal.Count; intCounter++)
                    {
                        lstRetVal[intCounter] = (strFilename_Partial + lstRetVal[intCounter].Trim()).Replace("**", "*");
                    }
                }
                else
                {
                    lstRetVal.Add("*.*");
                }

                return lstRetVal;
            }
        }

        /// <summary>
        /// event called when the User clicks the Load/Save button 
        /// </summary>
        void confirm()
        {
            if (event_Confirm != null)
                event_Confirm((object)this, new EventArgs());
            DialogResult = DialogResult.OK;
            Hide();
        }
    }

    /// <summary>
    /// instance of a DirectoryTree Item (file or folder)
    /// </summary>
    public class classTreeItem
    {
        /// <summary>
        /// list of tree item types
        /// </summary>
        public enum enuTreeItemType { file, directory, _num };

        /// <summary>
        /// defines this Tree-Item instance's type
        /// </summary>
        public enuTreeItemType eTreeItemType = enuTreeItemType.file;

        /// <summary>
        ///  points to this Tree-Item instance's parent in the DirectoryTree tree of TreeItems
        /// </summary>
        public classTreeItem Parent = null;

        /// <summary>
        /// lists the Tree-Items which are contained in this Folder (does not apply to files)
        /// </summary>
        public List<classTreeItem> lstContent = null;

        /// <summary>
        /// name of this Tree-Item not including its parent directories
        /// </summary>
        public string strName = "";

        /// <summary>
        /// full path of this Tree-Item
        /// </summary>
        public string strPath = "";

        /// <summary>
        ///  this Tree-Item's FileInfo
        /// </summary>
        public FileInfo fileInfo = null;

        /// <summary>
        /// points to the button that the User can select to select this Tree-Item
        /// </summary>
        public classButton btn = null;

        /// <summary>
        /// the number of Parent Directories determines this Tree-Item's tab-position in the DirectoryTree region
        /// </summary>
        public int intNumParents = 0;

        /// <summary>
        /// points to the GUI-FileDialog this Tree-Item belongs to
        /// </summary>
        FileDialog_GUI fdParent = null;

        /// <summary>
        /// instantiates an instance of the classTreeItem with a reference parameter pointing back to the GUI-FileDialog this instance belongs to
        /// </summary>
        /// <param name="_fdParent"></param>
        classTreeItem(ref FileDialog_GUI _fdParent)
        {
            fdParent = _fdParent;
        }

        /// <summary>
        /// returns an instance of a Tree-Item only if that tree item is not found in the calling GUI-FileDialog's TreeItem binary tree search engine
        /// </summary>
        /// <param name="_fdParent">pointer to calling parent GUI-FileDialog</param>
        /// <param name="strPath">path of the requested Tree-Item used to search the calling GUI-FileDialog's BinaryTree of TreeItems if one already exists</param>
        /// <returns></returns>
        public static classTreeItem New(ref FileDialog_GUI _fdParent, string strPath)
        {
            classTreeItem cRetVal = null;
            if (_fdParent != null)
            {
                if (_fdParent.TI_BinTree != null)
                {
                    cRetVal = _fdParent.TI_BinTree.Search(strPath);
                    if (cRetVal != null)
                        return cRetVal;
                }
            }

            cRetVal = new classTreeItem(ref _fdParent);
            cRetVal.strPath = strPath;
            return cRetVal;
        }

        /// <summary>
        /// type of view used to display the contents of the Tree-Item Folder(does not apply to files)
        /// </summary>
        classDraw_Content.enuViewStyle _eViewStyle = classDraw_Content.enuViewStyle.Medium_icons;
        public classDraw_Content.enuViewStyle eViewStyle
        {
            get { return _eViewStyle; }
            set
            {
                if (_eViewStyle != value)
                {
                    _eViewStyle = value;
                    fdParent.cDrawer_DirTree.Refreshed = false;
                    fdParent.regContent.IsRefreshed = false;
                }
            }
        }

        bool bolExpanded = false;
        /// <summary>
        /// true when the User has expanded this Folder (does not apply to files)
        /// </summary>
        public bool Expanded
        {
            get { return bolExpanded; }
            set
            {
                bolExpanded = value;
                fdParent.cDrawer_DirTree.Refreshed = false;
                fdParent.regDirTree.IsRefreshed = false;
                fdParent.regContent.IsRefreshed = false;
            }
        }

        /// <summary>
        /// loads this Folder's file/folder contents with no reference to a parent GUI-FileDialog - does not apply to Files
        /// </summary>
        public void setDirContents()
        {
            classTreeItem cCallingChild = null;
            setDirContents(ref cCallingChild);
        }

        /// <summary>
        /// loads this Folder's file/folder contents with a reference to a parent GUI-FileDialog - does not apply to Files
        /// </summary>
        /// <param name="cCallingChild"></param>
        public void setDirContents(ref classTreeItem cCallingChild)
        {
            lstContent = new List<classTreeItem>();

            // find all subdirectories of current directory
            try
            {
                List<string> lstSubDir = System.IO.Directory.GetDirectories(strPath).ToList<string>();
                for (int intSubDirCounter = 0; intSubDirCounter < lstSubDir.Count; intSubDirCounter++)
                {
                    if (cCallingChild == null || string.Compare(cCallingChild.strPath.ToUpper(), lstSubDir[intSubDirCounter].ToUpper()) != 0)
                    {
                        classTreeItem cSubDir = classTreeItem.New(ref fdParent, lstSubDir[intSubDirCounter]);
                        cSubDir.Parent = this;
                        cSubDir.strName = lstSubDir[intSubDirCounter].Substring(strPath.Length + (lstSubDir[intSubDirCounter][strPath.Length] == '\\' ? 1 : 0));

                        cSubDir.intNumParents = intNumParents + 1;
                        cSubDir.eTreeItemType = enuTreeItemType.directory;

                        fdParent.TI_BinTree.Insert(ref cSubDir);
                        lstContent.Add(cSubDir);
                    }
                    else
                        lstContent.Add(cCallingChild);
                }
            }
            catch (Exception)
            {
            }

            try
            {
                List<FileInfo> lstFiles = new List<FileInfo>();
                System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(strPath);
                string strThisSearchPattern = "*.*";

                List<FileInfo> lstNewFiles = dir.GetFiles(strThisSearchPattern).ToList<FileInfo>();

                for (int intFilesCounter = 0; intFilesCounter < lstNewFiles.Count; intFilesCounter++)
                {
                    classTreeItem cFile = classTreeItem.New(ref fdParent, lstNewFiles[intFilesCounter].FullName);
                    cFile.Parent = this;
                    cFile.strName = lstNewFiles[intFilesCounter].Name;

                    cFile.intNumParents = intNumParents + 1;
                    cFile.eTreeItemType = enuTreeItemType.file;
                    cFile.fileInfo = lstNewFiles[intFilesCounter];
                    fdParent.TI_BinTree.Insert(ref cFile);

                    lstContent.Add(cFile);
                }
                lstFiles.AddRange(lstNewFiles);
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// the binary-tree used to sort the DirectoryTree's Tree-Items
        /// </summary>
        public class classBinTree
        {
            /// <summary>
            /// this tree's root Element
            /// </summary>
            classBinTreeItem cRoot = null;

            /// <summary>
            /// instantiates an instance of the classBinTree to help sort/search for DirectoryTree TreeItems by their path names
            /// </summary>
            public classBinTree()
            {

            }

            /// <summary>
            /// searches this binary-tree for a Tree-Item specified by its Path name
            /// </summary>
            /// <param name="strPath">Path string used to specify which the Tree-Item being requested</param>
            /// <returns>a Tree-Item specified by the strPath parameter if such a Tree-Item is found in this Binary Tree</returns>
            public classTreeItem Search(string strPath)
            {
                strPath = strPath.ToUpper().Trim();
                classBinTreeItem cBin = cRoot;
                while (cBin != null)
                {
                    int intComparisonResult = string.Compare(strPath, cBin.key);
                    if (intComparisonResult > 0)
                        cBin = cBin.right;
                    else if (intComparisonResult < 0)
                        cBin = cBin.left;
                    else
                        return cBin.cTI;
                }
                return null;
            }

            /// <summary>
            /// inserts a Tree-Item into this Binary-tree
            /// replaces any existing Tree-Item with the specified path if one is found
            /// </summary>
            /// <param name="cTI_New">TreeItem to be inserted into the BinaryTree</param>
            public void Insert(ref classTreeItem cTI_New)
            {
                if (cTI_New == null) return;
                if (cRoot == null)
                {
                    cRoot = new classBinTreeItem(cTI_New.strPath.ToUpper().Trim(), ref cTI_New);
                    return;
                }

                classBinTreeItem cBin = cRoot;
                string strKey = cTI_New.strPath.ToUpper().Trim();
                while (true)
                {
                    int intComparison = string.Compare(strKey, cBin.key);
                    if (intComparison > 0)
                    {
                        if (cBin.right != null)
                            cBin = cBin.right;
                        else
                        {
                            cBin.right = new classBinTreeItem(strKey, ref cTI_New);
                            cBin.right.parent = cBin;
                            return;
                        }
                    }
                    else if (intComparison < 0)
                    {
                        if (cBin.left != null)
                            cBin = cBin.left;
                        else
                        {
                            cBin.left = new classBinTreeItem(strKey, ref cTI_New);
                            cBin.left.parent = cBin;
                            return;
                        }
                    }
                    else
                    { // its already inserted
                        if (cBin.parent != null)
                        {
                            classBinTreeItem cBin_New = new classBinTreeItem(strKey, ref cTI_New);

                            if (cBin.parent.left == cBin)
                                cBin.parent.left = cBin_New;
                            else
                                cBin.parent.right = cBin_New;

                            cBin_New.left = cBin.left;
                            cBin_New.right = cBin.right;
                            cBin_New.parent = cBin.parent;
                        }
                        return;
                    }
                }
            }

            /// <summary>
            /// List used to keep track of which Tree-Items are found in this Binary-Tree's traversal
            /// </summary>
            List<classBinTreeItem> lstBinTreeTraversalResults = new List<classBinTreeItem>();

            /// <summary>
            /// traverses this Binary-Tree In-Order and returns tree's content
            /// </summary>
            /// <returns></returns>
            public List<classBinTreeItem> Traverse()
            {
                lstBinTreeTraversalResults.Clear();
                Traverse_Recurse(ref cRoot);
                return lstBinTreeTraversalResults;
            }

            /// <summary>
            /// recursion function used to Traverse this tree
            /// </summary>
            /// <param name="cBin">BinTreeItem sent by reference being traversed recursively</param>
            void Traverse_Recurse(ref classBinTreeItem cBin)
            {
                if (cBin == null) return;
                Traverse_Recurse(ref cBin.right);
                lstBinTreeTraversalResults.Add(cBin);
                Traverse_Recurse(ref cBin.left);
            }

            /// <summary>
            /// instance of this binary-tree's elements
            /// </summary>
            public class classBinTreeItem
            {
                /// <summary>
                /// pointer to left child
                /// </summary>
                public classBinTreeItem left = null;
                /// <summary>
                /// pointer to right child
                /// </summary>
                public classBinTreeItem right = null;
                /// <summary>
                /// pointer to parent
                /// </summary>
                public classBinTreeItem parent = null;

                /// <summary>
                /// key used in search comparison = this Tree-Item's complete path
                /// </summary>
                public string key = "";

                /// <summary>
                /// pointer to the Directory Tree Item instance this Binary-Tree Item is associated with
                /// </summary>
                public classTreeItem cTI = null;

                /// <summary>
                /// instantiates a binary tree item - without specifying its content
                /// </summary>
                public classBinTreeItem() { }

                /// <summary>
                ///  instantiates a binary tree item - with specified conent
                /// </summary>
                /// <param name="strKey">path used to search/insert this Binary Tree item into the tree</param>
                /// <param name="_cTI">Directory Tree Item this Binary Tree Item is associated with</param>
                public classBinTreeItem(string strKey, ref classTreeItem _cTI)
                {
                    key = strKey;
                    cTI = _cTI;
                }
            }
        }
    }

    /// <summary>
    /// defines one of the 9 Regions on the GUI-FileDialog
    /// </summary>
    public class classRegion
    {
        /// <summary>
        /// pointer to this Region's parent GUI-FileDialog
        /// </summary>
        public FileDialog_GUI fd_Parent = null;

        /// <summary>
        /// list of Buttons currently available on the screen
        /// </summary>
        List<classButton> lstButtons = new List<classButton>();

        /// <summary>
        /// instance of the Sweep And Prune class used to find the different Buttons in this Region
        /// </summary>
        public classSweepAndPrune cSweepAndPrune = new classSweepAndPrune();

        classButton cBtnSelected = null;
        /// <summary>
        /// button currently selected by the user
        /// </summary>
        public classButton btnSelected
        {
            get { return cBtnSelected; }
            set
            {
                if (cBtnSelected != value)
                {
                    if (Region == FileDialog_GUI.enuRegions.ContentCurrentDirectory)
                    {
                        if (!fd_Parent.MultiSelect)
                        {
                            if (cBtnSelected != null)
                            {
                                cBtnSelected.Toggled = false;
                                cBtnSelected.Refreshed = false;
                            }
                        }
                    }
                    cBtnSelected = value;
                }
            }
        }

        /// <summary>
        /// adds one button to the Region
        /// </summary>
        /// <param name="recArea">area over which the button is found</param>
        /// <returns>instance of the button class created</returns>
        public classButton Button_Add(Rectangle recArea)
        {
            object objNull = null;
            return Button_Add(recArea, ref objNull);
        }

        /// <summary>
        /// adds a button to the region
        /// </summary>
        /// <param name="recArea">defines the area this button covers</param>
        /// <param name="obj">object class which this button is associated with</param>
        /// <returns></returns>
        public classButton Button_Add(Rectangle recArea, ref object obj)
        {
            classButton cBtnNew = new classButton();
            cBtnNew.obj = obj;
            cBtnNew.recArea = recArea;
            cBtnNew.cParentRegion = this;
            lstButtons.Add(cBtnNew);

            classSweepAndPrune.classElement cSPEle = new classSweepAndPrune.classElement();
            cSPEle.obj = (object)cBtnNew;
            cSPEle.rec = recArea;

            return cBtnNew;
        }


        bool bolHighlight = false;
        /// <summary>
        /// toggle that defines whether this button is highlighted or not
        /// </summary>
        public bool Highlight
        {
            get { return bolHighlight; }
            set
            {
                if (bolHighlight != value)
                {
                    bolHighlight = value;
                }
            }
        }


        bool bolIsRefreshed = false;
        /// <summary>
        /// determines whether this Region needs to be redrawn before being placed on the screen
        /// </summary>
        public bool IsRefreshed
        {
            get { return bolIsRefreshed; }
            set
            {
                if (bolIsRefreshed != value)
                {
                    bolIsRefreshed = value;

                    if (cScrollBarV != null)
                        cScrollBarV.Refreshed = false;
                    if (cScrollBarH != null)
                        cScrollBarH.Refreshed = false;

                    switch (Region)
                    {
                        case FileDialog_GUI.enuRegions.UserInput_TextInput:
                            {
                                classCharImage.clrBackgroundHighlight
                                    = classCharImage.clrForegroundIdle
                                    = clrForeGround;

                                classCharImage.clrBackgroundIdle
                                    = classCharImage.clrForegroundHighlight
                                    = clrBackGround;

                                classCharImage.font = font;
                            }
                            break;

                        case FileDialog_GUI.enuRegions.ContentCurrentDirectory:
                            {

                            }
                            break;
                    }
                }
            }
        }

        /// <summary>
        /// pointer to this instance used as a reference parameter in certain function calls
        /// </summary>
        classRegion cMyRef = null;

        /// <summary>
        /// instantiates an instance of this class
        /// </summary>
        /// <param name="_Region">this instance's enumerated type</param>
        /// <param name="_fd_Parent">pointer to this instance's parent GUI-FileDialog</param>
        public classRegion(FileDialog_GUI.enuRegions _Region, ref FileDialog_GUI _fd_Parent)
        {
            fd_Parent = _fd_Parent;
            eRegion = _Region;
            cMyRef = this;
            cScrollBarV = new classScrollBar(ref cMyRef);
            cScrollBarV.eType = classScrollBar.enuScrollBarType.Vertical;
            cScrollBarH = new classScrollBar(ref cMyRef);
            cScrollBarH.eType = classScrollBar.enuScrollBarType.Horizontal;

        }

        bool bolDrawBorder = true;
        /// <summary>
        /// determines whether the border of this Region is drawn or not
        /// </summary>
        public bool DrawBorder
        {
            get { return bolDrawBorder; }
            set
            {
                if (bolDrawBorder != value)
                {
                    bolDrawBorder = value;
                    IsRefreshed = false;
                }
            }
        }

        Font fnt = new Font("ms sans-serif", 10);
        /// <summary>
        /// font used to draw the text in this Region
        /// </summary>
        public Font font
        {
            get { return fnt; }
            set
            {
                fnt = value;
                IsRefreshed = false;
                switch (Region)
                {
                    case FileDialog_GUI.enuRegions.DirTree:
                        {
                            if (fd_Parent.cDrawer_DirTree != null)
                                fd_Parent.cDrawer_DirTree.Refreshed = false;
                        }
                        break;

                    case FileDialog_GUI.enuRegions.UserInput_Cancel:
                    case FileDialog_GUI.enuRegions.UserInput_Confirm:
                        {
                            if (fd_Parent != null)
                            {
                                if (cSweepAndPrune.lstElements.Count > 0)
                                {
                                    classButton cBtn = (classButton)cSweepAndPrune.lstElements[0].obj;
                                    fd_Parent.cUserInputButtonDrawer.Draw(ref cBtn);
                                    fd_Parent.DrawScreen();
                                }
                            }
                        }
                        break;

                    default:
                        {
                            if (fd_Parent != null)
                            {
                                fd_Parent.DrawScreen();
                            }
                        }
                        break;
                }

            }
        }

        SolidBrush _brBackground = null;
        /// <summary>
        /// color of this Region's background
        /// </summary>
        public SolidBrush brBackground
        {
            get
            {
                if (_brBackground == null)
                    _brBackground = new SolidBrush(ColorBackground);
                return _brBackground;
            }
        }

        Pen _pForeground = null;
        /// <summary>
        /// color of this Region's foreground
        /// </summary>
        public Pen pForeground
        {
            get
            {
                if (_pForeground == null)
                    _pForeground = new Pen(ColorForeground);
                return _pForeground;
            }
        }

        Pen _pBackground = null;
        /// <summary>
        /// Pen used for drawing foreground in this Region
        /// </summary>
        public Pen pBackground
        {
            get
            {
                if (_pBackground == null)
                    _pBackground = new Pen(ColorBackground);
                return _pBackground;
            }
        }

        SolidBrush _brForeground = null;
        /// <summary>
        /// brush used for drawing foreground in this Region
        /// </summary>
        public SolidBrush brForeground
        {
            get
            {
                if (_brForeground == null)
                    _brForeground = new SolidBrush(ColorForeground);
                return _brForeground;
            }
        }

        Color clrForeGround = Color.FromArgb(0, 1, 2);
        /// <summary>
        /// Color of this Region's Foreground
        /// </summary>
        public Color ColorForeground
        {
            get { return clrForeGround; }
            set
            {
                clrForeGround = value;
                _brForeground = null;
                _pForeground = null;
                IsRefreshed = false;
                if (ScrollBarH_Shown && cScrollBarH != null)
                    cScrollBarH.Refreshed = false;
                if (ScrollBarV_Shown && cScrollBarV != null)
                    cScrollBarV.Refreshed = false;

                switch (Region)
                {
                    case FileDialog_GUI.enuRegions.DirTree:
                        {

                            if (fd_Parent.cDrawer_DirTree != null)
                                fd_Parent.cDrawer_DirTree.Refreshed = false;
                        }
                        break;

                    case FileDialog_GUI.enuRegions.UserInput_Cancel:
                    case FileDialog_GUI.enuRegions.UserInput_Confirm:
                        {
                            if (cSweepAndPrune.lstElements.Count > 0)
                            {
                                classButton cBtn = (classButton)cSweepAndPrune.lstElements[0].obj;
                                fd_Parent.cUserInputButtonDrawer.Draw(ref cBtn);
                            }
                        }
                        break;

                    case FileDialog_GUI.enuRegions.UserInput_TextInput:
                        {
                            classCharImage.clrForegroundIdle
                                    = classCharImage.clrBackgroundHighlight
                                    = clrForeGround;

                        }
                        break;
                }
            }
        }

        Color clrBackGround = Color.FromArgb(254, 253, 252);
        /// <summary>
        /// color of this Region's Background
        /// </summary>
        public Color ColorBackground
        {
            get { return clrBackGround; }
            set
            {
                clrBackGround = value;
                _brBackground = null;
                _pBackground = null;
                IsRefreshed = false;
                if (Region == FileDialog_GUI.enuRegions.DirTree)
                    if (fd_Parent.cDrawer_DirTree != null)
                        fd_Parent.cDrawer_DirTree.Refreshed = false;

                switch (Region)
                {
                    case FileDialog_GUI.enuRegions.DirTree:
                        {

                            if (fd_Parent.cDrawer_DirTree != null)
                                fd_Parent.cDrawer_DirTree.Refreshed = false;
                        }
                        break;

                    case FileDialog_GUI.enuRegions.UserInput_Cancel:
                    case FileDialog_GUI.enuRegions.UserInput_Confirm:
                        {
                            if (cSweepAndPrune.lstElements.Count > 0)
                            {
                                classButton cBtn = (classButton)cSweepAndPrune.lstElements[0].obj;
                                fd_Parent.cUserInputButtonDrawer.Draw(ref cBtn);
                            }
                        }
                        break;

                    case FileDialog_GUI.enuRegions.UserInput_TextInput:
                        {
                            classCharImage.clrBackgroundIdle
                                    = classCharImage.clrForegroundHighlight
                                    = clrBackGround;
                        }
                        break;
                }
            }
        }


        bool bolIsFixedHeight = true;
        /// <summary>
        /// determine's whether this Region's Height varies with the Form's SizeChanges when the form's CanBeResized property is true (default false)
        /// </summary>
        public bool IsFixedHeight
        {
            get { return bolIsFixedHeight; }
            set { bolIsFixedHeight = value; }
        }

        bool bolIsFixedWidth = true;
        /// <summary>
        /// determine's whether this Region's Width varies with the Form's SizeChanges when the form's CanBeResized property is true (default false)
        /// </summary>
        public bool IsFixedWidth
        {
            get { return bolIsFixedWidth; }
            set { bolIsFixedWidth = value; }
        }

        /// <summary>
        /// this Region's Size as it appears on the form
        /// </summary>
        public Size size
        {
            get { return rec.Size; }
            set
            {
                if (_rec.Size != value)
                {
                    _rec.Size = value;
                    IsRefreshed = false;
                    fd_Parent.resize();
                }
            }
        }

        bool bolIsFixedTop = true;
        /// <summary>
        /// determine's whether this Region's Top varies with the Form's SizeChanges when the form's CanBeResized property is true (default false)
        /// </summary>
        public bool IsFixedTop
        {
            get { return bolIsFixedTop; }
            set { bolIsFixedTop = value; }
        }

        bool bolIsFixedLeft = true;
        /// <summary>
        /// determine's whether this Region's Left varies with the Form's SizeChanges when the form's CanBeResized property is true (default false)
        /// </summary>
        public bool IsFixedLeft
        {
            get { return bolIsFixedLeft; }
            set { bolIsFixedLeft = value; }
        }

        /// <summary>
        /// this Region's Location as it appears on the form
        /// </summary>
        public Point Location
        {
            get { return rec.Location; }
            set
            {
                if (_rec.Location != value)
                {
                    _rec.Location = value;
                    fd_Parent.resize();
                }
            }
        }

        /// <summary>
        /// sets this Region's Size and Location if the Form's SizeChanges AND the form's CanBeResized property is true (default false)
        /// </summary>
        public void ParentSizeChanged()
        {
            rec_SetToFitParent();
        }

        Rectangle _rec = new Rectangle();
        /// <summary>
        /// defines this regions location on the form 
        /// </summary>
        public Rectangle rec
        {
            get { return _rec; }
            set
            {
                if (_rec != value)
                {
                    _rec = value;

                    if (_rec.Height < 1)
                        _rec.Height = 1;
                    if (_rec.Width < 1)
                        _rec.Width = 1;
                    fd_Parent.resize();
                }
            }
        }

        RectangleF recPercentageForm = new RectangleF();
        /// <summary>
        /// when the form's CanBeResized property is true (default false)
        /// parameters that define the area of the form which this region occupies as a percentage of width & height of the parent form 
        /// all values are percentiles ranging from 0% -100% - overlapping regions are compared sequentially
        /// </summary>
        public RectangleF PercentageForm
        {
            get { return recPercentageForm; }
            set
            {
                recPercentageForm = value;
                rec_SetToFitParent();
                fd_Parent.DrawScreen();
            }
        }

        /// <summary>
        /// when the form's CanBeResized property is true (default false)
        /// resizes the Region according to its Specified re-sizing parameters
        /// </summary>
        public void rec_SetToFitParent()
        {
            int intWidthNew = IsFixedWidth ? _rec.Size.Width : (int)((double)fd_Parent.Width * (double)recPercentageForm.Width / 100.0);
            int intHeightNew = IsFixedHeight ? _rec.Size.Height : (int)((double)fd_Parent.Height * (double)recPercentageForm.Height / 100.0);

            int intLeftNew = IsFixedLeft ? _rec.Left : (int)((double)fd_Parent.Width * (double)recPercentageForm.Left / 100.0);
            int intTopNew = IsFixedTop ? _rec.Top : (int)((double)fd_Parent.Height * (double)recPercentageForm.Top / 100.0);

            Size szNew = new Size(intWidthNew, intHeightNew);

            Point ptLocation_New = new Point();
            if (Anchor == null)
            {
                ptLocation_New = new Point(intLeftNew, intTopNew);
            }
            else
            {
                Point ptReference = new Point();
                switch (Anchor.eAnchorPoint)
                {
                    case classAnchor.enuAnchorPoints.TopLeft:
                        {
                        }
                        break;

                    case classAnchor.enuAnchorPoints.Top:
                        {
                            ptReference = new Point((fd_Parent.Width - rec.Width) / 2, 0);
                        }
                        break;

                    case classAnchor.enuAnchorPoints.TopRight:
                        {
                            ptReference = new Point(fd_Parent.Width, 0);
                        }
                        break;

                    case classAnchor.enuAnchorPoints.Right:
                        {
                            ptReference = new Point(fd_Parent.Width, (fd_Parent.Height - rec.Height) / 2);
                        }
                        break;

                    case classAnchor.enuAnchorPoints.BottomRight:
                        {
                            ptReference = new Point(fd_Parent.Width, fd_Parent.Height);
                        }
                        break;

                    case classAnchor.enuAnchorPoints.Bottom:
                        {
                            ptReference = new Point((fd_Parent.Width - rec.Width) / 2, fd_Parent.Height);
                        }
                        break;

                    case classAnchor.enuAnchorPoints.BottomLeft:
                        {
                            ptReference = new Point(0, fd_Parent.Height);
                        }
                        break;

                    case classAnchor.enuAnchorPoints.Left:
                        {
                            ptReference = new Point(0, (fd_Parent.Height - rec.Height) / 2);
                        }
                        break;
                }
                ptLocation_New = new Point(ptReference.X + Anchor.ptRelToAnchorPoint.X, ptReference.Y + Anchor.ptRelToAnchorPoint.Y);
            }
            _rec = new Rectangle(ptLocation_New, szNew);
            recVisible = new Rectangle(recVisible.Location, rec.Size);

            IsRefreshed = false;
            recVisible_Set();
        }

        bool bolSettingVisible = false;
        /// <summary>
        /// determines which part of the region is visible and drawn to the screen given its Size & scroll-bar values
        /// </summary>
        public void recVisible_Set()
        {
            if (bmp == null || bolSettingVisible) return;
            bolSettingVisible = true;
            try
            {
                int intWidth = rec.Width;
                int intHeight = rec.Height;
                int intTop = 0;
                int intLeft = 0;

                Size szFont = TextRenderer.MeasureText("X", fnt);

                if (ScrollBar_V)
                {
                    if (Region == FileDialog_GUI.enuRegions.DirTree && fd_Parent.cBtnUnderMouse != null && fd_Parent.cBtnUnderMouse.eButtonType == classButton.enuButtonType.ExpandCollapse)
                    {
                        try
                        {
                            cScrollBarV.Value = (double)fd_Parent.cBtnUnderMouse.recArea.Top / (double)szBmp.Height;
                        }
                        catch (Exception)
                        {
                        }
                    }

                    intTop = (int)(cScrollBarV.Value * ((double)(szBmp.Height) - (double)(rec.Height - (ScrollBar_H ? ScrollBarWidth : 0))));
                    cScrollBarV.Step_Large = (double)rec.Height / (double)szBmp.Height;
                    cScrollBarV.Step_Small = (double)szFont.Height / (double)(szBmp.Height - rec.Height);
                }

                if (ScrollBar_H)
                {
                    intLeft = (int)(cScrollBarH.Value * ((double)(szBmp.Width) - (double)(rec.Width - (ScrollBar_V ? ScrollBarWidth : 0))));

                    cScrollBarH.Step_Large = (double)rec.Width / (double)szBmp.Width;
                    cScrollBarH.Step_Small = (double)szFont.Width / (double)(szBmp.Width - rec.Width);
                }

                Size szNew = new Size(intWidth - 2, intHeight - 2);
                Point ptNew = new Point(intLeft + 1, intTop + 1);

                if (szNew.Width != recVisible.Width
                    || szNew.Height != recVisible.Height
                    || ptNew.X != recVisible.X
                    || ptNew.Y != recVisible.Y)
                {
                    ptRecVisible_Offset.X += (ptNew.X - recVisible.X);
                    ptRecVisible_Offset.Y += (ptNew.Y - recVisible.Y);
                    recVisible = new Rectangle(ptNew, szNew);

                    switch (Region)
                    {
                        case FileDialog_GUI.enuRegions.ContentCurrentDirectory:
                            {

                                fd_Parent.cDrawer_Content.DrawButtonsOnScreen(fd_Parent.cTICurrent != null ? fd_Parent.cTICurrent.eViewStyle : classDraw_Content.enuViewStyle.List);
                            }
                            break;

                        case FileDialog_GUI.enuRegions.DirTree:
                            {
                                fd_Parent.cDrawer_DirTree.DrawButtonsOnScreen();
                            }
                            break;
                    }
                }

            }
            catch (Exception)
            {
            }

            bolSettingVisible = false;
        }

        Size _szBmp = new Size();
        /// <summary>
        /// used when by regContent & DirTree - large Regions first Define the locations of all theit buttons contained in region the size of szBmp
        /// then only draws what the User expects from that Region on the form
        /// </summary>
        public Size szBmp
        {
            get
            {
                switch (Region)
                {
                    case FileDialog_GUI.enuRegions.ContentCurrentDirectory:
                    case FileDialog_GUI.enuRegions.DirTree:
                        return _szBmp;

                    default:
                        return bmp.Size;
                }
            }
            set
            {
                _szBmp = value;
                recVisible_Set();
            }
        }

        Bitmap _bmp = null;
        /// <summary>
        /// bitmap of this Region's sub-region that is currently drawn and sampled from to draw on the screen
        /// </summary>
        public Bitmap bmp
        {
            get
            {
                return _bmp;
            }
            set
            {
                _bmp = value;
            }
        }

        bool bolBlendBackground = false;
        /// <summary>
        /// determines whether this Region is drawn to blend into the parent GUI-FileDialog
        /// </summary>
        public bool BlendBackground
        {
            get { return bolBlendBackground; }
            set
            {
                if (bolBlendBackground != value)
                {
                    bolBlendBackground = value;
                    IsRefreshed = false;
                }
            }
        }

        /// <summary>
        /// used by regContent & regDirTree to limit size of region's bitmap to what is immediately(visible plus area for small scrolling values) required on the screen 
        /// </summary>
        public Point ptRecVisible_Offset = new Point();

        /// <summary>
        /// determines whether the ptRecVisible_Offset value is used when drawing this Region on the GUI-FileDialog
        /// </summary>
        public bool bolRecVisible_OffSet_Valid = false;

        /// <summary>
        /// portion of this region's area that is displayed on output form - 
        /// </summary>
        Rectangle _recVisible = new Rectangle(0, 0, 100, 100);
        public Rectangle recVisible
        {
            get { return _recVisible; }
            set
            {
                _recVisible = value;
            }
        }


        FileDialog_GUI.enuRegions eRegion = FileDialog_GUI.enuRegions._num;
        /// <summary>
        /// identifies this Region among the list of Regions in the GUI-FileDialog
        /// </summary>
        public FileDialog_GUI.enuRegions Region
        {
            get { return eRegion; }
        }


        #region Scroll_Bars
        bool bolScrollBarV_Shown = true;
        /// <summary>
        /// determines whether this Region may or may not draw a Vertical scroll bar i.e. DirTree only
        /// </summary>
        public bool ScrollBarV_Shown
        {
            get { return bolScrollBarV_Shown; }
            set { bolScrollBarV_Shown = value; }
        }

        bool bolScrollBarH_Shown = true;
        /// <summary>
        /// determines whether this Region may or may not draw a Horizontal scroll bar i.e. Content only
        /// </summary>
        public bool ScrollBarH_Shown
        {
            get { return bolScrollBarH_Shown; }
            set { bolScrollBarH_Shown = value; }
        }


        public classScrollBar cScrollBarV = null;
        /// <summary>
        /// image of this Region's Vertical Scroll bar as it currently appears on the GUI-FileDialog
        /// </summary>
        public Bitmap ScrollBar_V_Image
        {
            get
            {
                try
                {
                    if (cScrollBarV != null && cScrollBarV.bmp != null)
                        return cScrollBarV.bmp;
                    else return null;
                }
                catch (Exception)
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// image of this Region's Horizontal Scroll bar as it currently appears on the GUI-FileDialog
        /// </summary>
        public Bitmap ScrollBar_H_Image
        {
            get
            {
                try
                {
                    if (cScrollBarH != null && cScrollBarH.bmp != null) return cScrollBarH.bmp;
                    else return null;
                }
                catch (Exception)
                {
                    return null;
                }
                if (cScrollBarH != null && cScrollBarH.bmp != null) return cScrollBarH.bmp;
            }
        }

        /// <summary>
        /// pointer to the instance of this Region's Horizontal classScrollBar if one exists
        /// </summary>
        public classScrollBar cScrollBarH = null;

        int intScrollBarWidth = 20;
        /// <summary>
        /// Thickness of the Region's scroll bar
        /// </summary>
        public int ScrollBarWidth
        {
            get { return intScrollBarWidth; }
            set { intScrollBarWidth = value; }
        }

        bool bolScrollBar_V = false;
        /// <summary>
        /// determines whether this Region requires a vertical scroll-bar at the moment (only if ScrollBar_V is true)
        /// </summary>
        public bool ScrollBar_V
        {
            get
            {
                if (!bolScrollBarV_Shown) return false;
                if (bmp == null)
                    _bmp = new Bitmap(rec.Width, rec.Height);
                bool bolScrollBar_V_New = (_bmp.Height > rec.Height - (ScrollBarH_Shown && cScrollBarH.Step_Large < 1.0 ? ScrollBarWidth : 0));
                if (bolScrollBar_V != bolScrollBar_V_New)
                {
                    recVisible = new Rectangle(recVisible.Left, 0, rec.Width, rec.Height);
                    cScrollBarV.Value = 0;
                }
                bolScrollBar_V = bolScrollBar_V_New;
                return bolScrollBar_V;
            }
        }

        /// <summary>
        /// changes this Region's Vertical Scroll bar by a specified step size
        /// </summary>
        /// <param name="dblStep">size of step this scroll bar's value is to be changed</param>
        public void Scroll_V(double dblStep)
        {
            double dblScrollValue_New = cScrollBarV.Value + dblStep;

            if (dblScrollValue_New < cScrollBarV.Min)
                dblScrollValue_New = cScrollBarV.Min;
            if (dblScrollValue_New > cScrollBarV.Max)
                dblScrollValue_New = cScrollBarV.Max;

            cScrollBarV.Value = dblScrollValue_New;
        }


        bool bolScrollBar_H = false;
        /// <summary>
        /// determines whether this Region's Horizontal scroll needs to be drawn (only if this Region's ScrollBar_H is true)
        /// </summary>
        public bool ScrollBar_H
        {
            get
            {
                if (!bolScrollBarH_Shown) return false;
                if (bmp == null)
                {
                    _bmp = new Bitmap(rec.Width, rec.Height);
                }
                //return false;
                bool bolScrollBar_H_New = (_bmp.Width > rec.Width - (ScrollBarV_Shown && cScrollBarV.Step_Large < 1.0 ? ScrollBarWidth : 0));
                if (bolScrollBar_H != bolScrollBar_H_New)
                {
                    recVisible = new Rectangle(recVisible.Left, 0, rec.Width, rec.Height);
                    cScrollBarV.Value = 0;
                }
                bolScrollBar_H = bolScrollBar_H_New;

                return bolScrollBar_H;
            }
        }

        /// <summary>
        /// changes this Region's Horizontal Scroll bar value by an amount equal to the parameter specified
        /// </summary>
        /// <param name="dblStep">amount by which the Horizontal Scroll bar is to be changed</param>
        public void Scroll_H(double dblStep)
        {

            double dblScrollValue_New = cScrollBarH.Value + dblStep;

            if (dblScrollValue_New < cScrollBarH.Min)
                dblScrollValue_New = cScrollBarH.Min;
            if (dblScrollValue_New > cScrollBarH.Max)
                dblScrollValue_New = cScrollBarH.Max;

            cScrollBarH.Value = dblScrollValue_New;
        }
        #endregion

        /// <summary>
        /// information that tells the GUI-FileDialog where and how to position and resize this Region when the GUI-FileDialog's CanBeREsized property is true(default false)
        /// </summary>
        public classAnchor Anchor = null;
    }

    /// <summary>
    /// classAnchor contains information used to reposition/resize a region when the GUI-FIleDialog's CanBeResized property is true(default false)
    /// </summary>
    public class classAnchor
    {
        public enum enuAnchorPoints { TopLeft, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left, _num };
        public enuAnchorPoints eAnchorPoint = enuAnchorPoints.TopLeft;
        public Point ptRelToAnchorPoint = new Point(0, 0);
    }

    /// <summary>
    /// scroll bars are used to determine what part of a Region's contents are to be displayed on the screen
    /// </summary>
    public class classScrollBar
    {
        /// <summary>
        /// instantiates an instance of the classScrollBar
        /// </summary>
        /// <param name="cRegionParent">a pointer to this Scroll Bar's parent Region</param>
        public classScrollBar(ref classRegion cRegionParent)
        {
            cParent = cRegionParent;
        }

        /// <summary>
        /// instance of the SweepAndPrune algorithm used to determine what part of the Scroll bar the User's mouse cursor is over
        /// </summary>
        public classSweepAndPrune cSweepAndPrune = new classSweepAndPrune();

        /// <summary>
        /// specifies whether this scroll-bar is either horizontal or vertical
        /// </summary>
        public enum enuScrollBarType { Horizontal, Vertical, _num };

        /// <summary>
        /// specifies which of three regions of the Scroll bar is being interacted with by the User
        /// </summary>
        public enum enuScrollBar_Regions { BeforeSlider, Slider, AfterSlider, _num };

        /// <summary>
        /// point relative to the Top-Left of this Scroll bar's Slider is being grabbed by the User's Mouse
        /// </summary>
        public Point ptGrab = new Point(-1, -1);

        bool bolGrab = false;
        /// <summary>
        /// is set when the user grab's this scrollBar's slider
        /// </summary>
        public bool Grab
        {
            get { return bolGrab; }
            set { bolGrab = value; }
        }

        double dblMax = 1;
        /// <summary>
        /// maximum value this scroll bar can have (default 1.0)
        /// </summary>
        public double Max
        {
            get { return dblMax; }
            set { dblMax = value; }
        }

        double dblMin = 0;
        /// <summary>
        /// minimum value this scroll bar can have (default 0.0)
        /// </summary>
        public double Min
        {
            get { return dblMin; }
            set { dblMin = value; }
        }

        bool bolRefreshed = false;
        /// <summary>
        /// determines whether this scroll-bar needs to be redrawn before being copies onto its parent GUI-FileDialog form
        /// </summary>
        public bool Refreshed
        {
            get { return bolRefreshed; }
            set { bolRefreshed = value; }
        }

        double _dblValue = 0;
        /// <summary>
        /// scroll-bar's value that determines what part of its parent region is drawn to the GUI-FileDialog
        /// </summary>
        public double Value
        {
            get { return _dblValue; }
            set
            {
                if (_dblValue != value && !double.IsNaN(value))
                {
                    _dblValue = value;
                    if (_dblValue < dblMin)
                        _dblValue = dblMin;
                    if (_dblValue > dblMax)
                        _dblValue = dblMax;

                    Refreshed = false;
                    cParent.recVisible_Set();
                }
            }
        }

        double dblStep_Large = 0.2;
        /// <summary>
        /// Step-value by which the Scroll bar's Value is changed whenever the User clicks on either side of this scroll bar's Slider
        /// </summary>
        public double Step_Large
        {
            get { return dblStep_Large; }
            set
            {
                dblStep_Large = value;
            }
        }

        double dblStep_Small = 0.2;
        /// <summary>
        /// step-value by which the scroll bar's value is changed whenever the User turns the MouseWheel over this ScrollBar or its parent Region
        /// </summary>
        public double Step_Small
        {
            get { return dblStep_Small; }
            set { dblStep_Small = value; }
        }

        /// <summary>
        /// specifies whether this is a Horizontal or Vertical ScrollBar
        /// </summary>
        public enuScrollBarType eType = enuScrollBarType.Horizontal;

        /// <summary>
        /// a pointer to this ScrollBar's parent Region - Region which it is associated with
        /// </summary>
        public classRegion cParent = null;

        /// <summary>
        /// minimum size which the ScrollBar's Slider will be drawn (size is a function of Large Step 
        /// which is derived from the ratio between the Region's Visible size & the size of the Region's content)
        /// </summary>
        const int conSliderMinWidth = 5;

        Bitmap _bmp = null;
        /// <summary>
        /// current bitmap of this ScrollBar which is copied and drawn onto the GUI-FileDialog
        /// </summary>
        public Bitmap bmp
        {
            get
            {
                if (!Refreshed)
                {
                    cSweepAndPrune.lstElements.Clear();

                    switch (eType)
                    {
                        case enuScrollBarType.Horizontal:
                            {
                                Size sz = recArea.Size;

                                int intLargeSize = (int)((double)sz.Width * dblStep_Large);

                                int intLeft = (int)((double)(sz.Width - intLargeSize) * Value);
                                _bmp = new Bitmap(sz.Width, sz.Height);
                                SolidBrush brBackGround = cParent.brBackground;
                                Pen pForeground = cParent.pForeground;

                                using (Graphics g = Graphics.FromImage(_bmp))
                                {
                                    g.FillRectangle(brBackGround, 0, 0, _bmp.Width, _bmp.Height);
                                    g.DrawRectangle(pForeground, 0, 0, _bmp.Width - 1, _bmp.Height - 1);
                                    g.FillRectangle(new SolidBrush(cParent.ColorForeground), intLeft, 0, intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth, sz.Height);
                                }
                                classSweepAndPrune.classElement cEle_BeforeSlider = new classSweepAndPrune.classElement();
                                cEle_BeforeSlider.obj = (object)enuScrollBar_Regions.BeforeSlider;
                                cEle_BeforeSlider.rec = new Rectangle(0, 0, intLeft, sz.Height);
                                cSweepAndPrune.Add(ref cEle_BeforeSlider);

                                classSweepAndPrune.classElement cEle_Slider = new classSweepAndPrune.classElement();
                                cEle_Slider.obj = (object)enuScrollBar_Regions.Slider;
                                cEle_Slider.rec = new Rectangle(intLeft, 0, (intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth), sz.Height);
                                cSweepAndPrune.Add(ref cEle_Slider);

                                classSweepAndPrune.classElement cEle_AfterSlider = new classSweepAndPrune.classElement();
                                cEle_AfterSlider.obj = (object)enuScrollBar_Regions.AfterSlider;
                                cEle_AfterSlider.rec = new Rectangle(intLeft + (intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth), 0, sz.Width - intLeft - (intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth), sz.Height);
                                cSweepAndPrune.Add(ref cEle_AfterSlider);
                            }
                            break;

                        case enuScrollBarType.Vertical:
                            {
                                Size sz = recArea.Size;

                                int intLargeSize = (int)((double)sz.Height * dblStep_Large);
                                int intTop = (int)((double)(sz.Height - intLargeSize) * Value);
                                _bmp = new Bitmap(sz.Width, sz.Height);
                                SolidBrush brBackGround = cParent.brBackground;
                                Pen pForeground = cParent.pForeground;

                                using (Graphics g = Graphics.FromImage(_bmp))
                                {
                                    g.FillRectangle(brBackGround, 0, 0, _bmp.Width, _bmp.Height);
                                    g.DrawRectangle(pForeground, 0, 0, _bmp.Width - 1, _bmp.Height - 1);
                                    g.FillRectangle(new SolidBrush(cParent.ColorForeground), 0, intTop, sz.Width, (intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth));
                                }

                                classSweepAndPrune.classElement cEle_BeforeSlider = new classSweepAndPrune.classElement();
                                cEle_BeforeSlider.obj = (object)enuScrollBar_Regions.BeforeSlider;
                                cEle_BeforeSlider.rec = new Rectangle(0, 0, sz.Width, intTop);
                                cSweepAndPrune.Add(ref cEle_BeforeSlider);

                                classSweepAndPrune.classElement cEle_Slider = new classSweepAndPrune.classElement();
                                cEle_Slider.obj = (object)enuScrollBar_Regions.Slider;
                                cEle_Slider.rec = new Rectangle(0, intTop, sz.Width, (intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth));
                                cSweepAndPrune.Add(ref cEle_Slider);

                                classSweepAndPrune.classElement cEle_AfterSlider = new classSweepAndPrune.classElement();
                                cEle_AfterSlider.obj = (object)enuScrollBar_Regions.AfterSlider;
                                cEle_AfterSlider.rec = new Rectangle(0, intTop + (intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth), sz.Width, sz.Height - intTop - (intLargeSize > conSliderMinWidth ? intLargeSize : conSliderMinWidth));
                                cSweepAndPrune.Add(ref cEle_AfterSlider);
                            }
                            break;
                    }
                    if (cParent.BlendBackground)
                        _bmp.MakeTransparent(cParent.brBackground.Color);

                    Refreshed = true;
                }
                return _bmp;
            }
        }

        Rectangle _recArea = new Rectangle();
        /// <summary>
        /// rectangle which defines the region this ScrollBar occupies on the GUI-FileDialog
        /// </summary>
        public Rectangle recArea
        {
            get { return _recArea; }
            set { _recArea = value; }
        }

    }

    /// <summary>
    /// class used to hold and retrieve images of the Character 'buttons' used in the UserInput_TextInput Region
    /// </summary>
    public class classCharImage
    {
        #region Char_Image
        /// <summary>
        /// class that defines the links of the CharImage binary tree
        /// </summary>
        public class classCharImageTreeLink
        {
            /// <summary>
            /// pointer to left child in Binary Tree
            /// </summary>
            public classCharImage left = null;
            /// <summary>
            /// pointer to right child in Binary tree
            /// </summary>
            public classCharImage right = null;
        }

        /// <summary>
        /// a pointer to the child nodes attached to this Binary-Tree element
        /// </summary>
        public classCharImageTreeLink cLinks = new classCharImageTreeLink();

        /// <summary>
        /// character which this instance of the CharImage class represents - used as the search key in the Binary Tree
        /// </summary>
        public char chr = ' ';

        /// <summary>
        /// bitmap of this character's idle-appearance
        /// </summary>
        public Bitmap bmp = null;

        /// <summary>
        /// bitmap of this character's highlight-appearance
        /// </summary>
        public Bitmap bmpHighlight = null;

        #endregion

        /// <summary>
        /// either retrieves an existing image from the Binary-Tree through a call to Search()
        /// or creates an instance of CharImage class, inserts it into the tree and returns it to the calling function
        /// </summary>
        /// <param name="chrSearch"></param>
        /// <returns></returns>
        public static classCharImage get(char chrSearch)
        {
            classCharImage cCI_RetVal = search(chrSearch);
            if (cCI_RetVal == null)
            {
                int intNum = 64;
                Size szTest = TextRenderer.MeasureText("".PadRight(intNum, chrSearch), fnt);
                Size szChar = new Size(szTest.Width / intNum + 1, szTest.Height);

                cCI_RetVal = new classCharImage();
                cCI_RetVal.chr = chrSearch;
                cCI_RetVal.bmp = new Bitmap(szChar.Width, szChar.Height);
                using (Graphics g = Graphics.FromImage(cCI_RetVal.bmp))
                {
                    g.FillRectangle(brBackgroundIdle, 0, 0, szChar.Width, szChar.Height);
                    g.DrawString(chrSearch.ToString(), fnt, brForegroundIdle, new Point(0, 0));
                }

                cCI_RetVal.bmpHighlight = new Bitmap(szChar.Width, szChar.Height);
                using (Graphics g = Graphics.FromImage(cCI_RetVal.bmpHighlight))
                {
                    g.FillRectangle(brBackgroundHighlight, 0, 0, szChar.Width, szChar.Height);
                    g.DrawString(chrSearch.ToString(), fnt, brForegroundHighlight, new Point(0, 0));
                }

                Insert(ref cCI_RetVal);
            }
            return cCI_RetVal;
        }

        #region Static_Data
        /// <summary>
        /// searches the binary tree for the requested Character image
        /// </summary>
        /// <param name="chrSearch">character requested</param>
        /// <returns></returns>
        static classCharImage search(char chrSearch)
        {
            classCharImage cCI = cTree;
            while (cCI != null)
            {
                if (cCI.chr > chrSearch)
                    cCI = cCI.cLinks.right;
                else if (cCI.chr < chrSearch)
                    cCI = cCI.cLinks.left;
                else
                    return cCI;
            }
            return null;
        }

        /// <summary>
        /// inserts a new instance of CharImage into the Binary Tree
        /// </summary>
        /// <param name="cCI_Insert">pointer to the CharImage class to be inserted into the tree</param>
        static void Insert(ref classCharImage cCI_Insert)
        {
            if (cTree == null)
            {
                cTree = cCI_Insert;
                return;
            }

            classCharImage cCI = cTree;

            do
            {
                if (cCI.chr > cCI_Insert.chr)
                {
                    if (cCI.cLinks.right == null)
                    {
                        cCI.cLinks.right = cCI_Insert;
                        return;
                    }
                    else
                        cCI = cCI.cLinks.right;
                }
                else if (cCI.chr < cCI_Insert.chr)
                {
                    if (cCI.cLinks.left == null)
                    {
                        cCI.cLinks.left = cCI_Insert;
                        return;
                    }
                    else
                        cCI = cCI.cLinks.left;
                }
            } while (true);
        }

        static classCharImage _cTree = null;
        /// <summary>
        /// pointer to the root of the Binary tree
        /// </summary>
        public static classCharImage cTree
        { 
        get { return _cTree; }
        set { _cTree = value; }
        }

        static Font fnt = new Font("ms san-serif", 8);
        /// <summary>
        /// Font currently used - changing the font resets the Binary-Tree to null
        /// </summary>
        public static Font font
        {
            get { return fnt; }
            set
            {
                if (fnt.Style != value.Style || fnt.Size != value.Size || string.Compare(fnt.FontFamily.Name, value.FontFamily.Name) != 0)
                {
                    fnt = value;
                    cTree = null;
                }
            }
        }

        #endregion

        #region Colors
        static SolidBrush _brForegroundIdle = null;
        /// <summary>
        /// brush used to draw the foreground of all the idle characters bitmaps in the tree
        /// </summary>
        static SolidBrush brForegroundIdle
        {
            get
            {
                if (_brForegroundIdle == null)
                    _brForegroundIdle = new SolidBrush(_clrForegroundIdle);
                return _brForegroundIdle;
            }
        }

        static Color _clrForegroundIdle = Color.Black;
        /// <summary>
        /// Color used to draw the Foreground of all the idle character bitmaps in the tree
        /// </summary>
        public static Color clrForegroundIdle
        {
            get { return _clrForegroundIdle; }
            set
            {
                if (_clrForegroundIdle.R != value.R || _clrForegroundIdle.G != value.G || _clrForegroundIdle.B != value.B | _clrForegroundIdle.A != value.A)
                {
                    _clrForegroundIdle = value;
                    _brForegroundIdle = null;
                    cTree = null;
                }
            }
        }

        static SolidBrush _brForegroundHighlight = null;
        /// <summary>
        /// brush used to draw all the highlight bitmaps in the tree
        /// </summary>
        static SolidBrush brForegroundHighlight
        {
            get
            {
                if (_brForegroundHighlight == null)
                    _brForegroundHighlight = new SolidBrush(_clrForegroundHighlight);
                return _brForegroundHighlight;
            }
        }

        static Color _clrForegroundHighlight = Color.White;
        /// <summary>
        /// color used to draw all the highlight bitmaps in the tree
        /// </summary>
        public static Color clrForegroundHighlight
        {
            get { return _clrForegroundHighlight; }
            set
            {
                if (_clrForegroundHighlight.R != value.R || _clrForegroundHighlight.G != value.G || _clrForegroundHighlight.B != value.B | _clrForegroundHighlight.A != value.A)
                {
                    _clrForegroundHighlight = value;
                    _brForegroundHighlight = null;
                    cTree = null;
                }
            }
        }

        static SolidBrush _brBackgroundIdle = null;
        /// <summary>
        /// brush used to draw all the idle-background bitmaps in the binary tree
        /// </summary>
        static SolidBrush brBackgroundIdle
        {
            get
            {
                if (_brBackgroundIdle == null)
                    _brBackgroundIdle = new SolidBrush(_clrBackgroundIdle);
                return _brBackgroundIdle;
            }
        }

        static Color _clrBackgroundIdle = Color.White;
        /// <summary>
        /// color used to draw all the idle-backgrounds in the binary tree
        /// </summary>
        public static Color clrBackgroundIdle
        {
            get { return _clrBackgroundIdle; }
            set
            {
                if (_clrBackgroundIdle.R != value.R || _clrBackgroundIdle.G != value.G || _clrBackgroundIdle.B != value.B | _clrBackgroundIdle.A != value.A)
                {
                    _clrBackgroundIdle = value;
                    _brBackgroundIdle = null;
                    _brForegroundHighlight = null;
                    cTree = null;
                }
            }
        }

        static SolidBrush _brBackgroundHighlight = null;
        /// <summary>
        /// brush used to draw all the highlight-backgrounds in the binary tree
        /// </summary>
        static SolidBrush brBackgroundHighlight
        {
            get
            {
                if (_brBackgroundHighlight == null)
                    _brBackgroundHighlight = new SolidBrush(_clrBackgroundHighlight);
                return _brBackgroundHighlight;
            }
        }

        static Color _clrBackgroundHighlight = Color.Black;
        /// <summary>
        /// color used to draw all the highlight-backgrounds in the binary tree
        /// </summary>
        public static Color clrBackgroundHighlight
        {
            get { return _clrBackgroundHighlight; }
            set
            {
                if (_clrBackgroundHighlight.R != value.R || _clrBackgroundHighlight.G != value.G || _clrBackgroundHighlight.B != value.B | _clrBackgroundHighlight.A != value.A)
                {
                    _clrBackgroundHighlight = value;
                    _brBackgroundHighlight = null;
                    _brForegroundIdle = null;
                    cTree = null;
                }
            }
        }

        #endregion

    }
   
    /// <summary>
    /// class used to draw the interactive user-input Regions (buttons) i.e. Confirm & Cancel
    /// </summary>
    public class classDraw_UserInput_Button
    {
        /// <summary>
        /// pointer to the GUI-FileDialong associated with this class
        /// </summary>
        FileDialog_GUI fdGUIParent = null;

        /// <summary>
        /// instantiates an instance of this class
        /// </summary>
        /// <param name="fdGUI">pointer to the GUI-FileDialog associated with this class</param>
        public classDraw_UserInput_Button(ref FileDialog_GUI fdGUI)
        {
            fdGUIParent = fdGUI;
        }

        /// <summary>
        /// draws the bitmap for the button received as a reference parameter
        /// </summary>
        /// <param name="cBtn">button to be drawn</param>
        public void Draw(ref classButton cBtn)
        {
            cBtn.bmp = new Bitmap(cBtn.cParentRegion.rec.Width, cBtn.cParentRegion.rec.Height);
            using (Graphics g = Graphics.FromImage(cBtn.bmp))
            {
                g.FillRectangle(cBtn.cParentRegion.brBackground, 0, 0, cBtn.bmp.Width, cBtn.bmp.Height);
                g.DrawString(cBtn.Text, cBtn.cParentRegion.font, cBtn.cParentRegion.brForeground, new Point(1, 1));
            }

            SolidBrush brAlt_Bacground = cBtn.cParentRegion.BlendBackground
                                             ? new SolidBrush(Color.FromArgb((cBtn.cParentRegion.brBackground.Color.R + 255) % 256,
                                                                             (cBtn.cParentRegion.brBackground.Color.G + 255) % 256,
                                                                             (cBtn.cParentRegion.brBackground.Color.B + 255) % 256))
                                             : cBtn.cParentRegion.brBackground;

            cBtn.bmpHighlight = new Bitmap(cBtn.cParentRegion.rec.Width, cBtn.cParentRegion.rec.Height);
            using (Graphics g = Graphics.FromImage(cBtn.bmpHighlight))
            {
                g.FillRectangle(cBtn.cParentRegion.brForeground, 0, 0, cBtn.bmp.Width, cBtn.bmp.Height);
                g.DrawRectangle(new Pen(brAlt_Bacground), 0, 0, cBtn.bmp.Width - 1, cBtn.bmp.Height - 1);
                g.DrawString(cBtn.Text, cBtn.cParentRegion.font, brAlt_Bacground, new Point(1, 1));
            }
        }
    }

    /// <summary>
    /// class used to draw the CurrentDirectoryContent Region to the screen
    /// all button(files & folders) locations and sizes are defined in memory then a sub-region larger 50% larger than the visible region is drawn to a bitmap then sampled to the screen
    /// </summary>
    public class classDraw_Content
    {
        /// <summary>
        /// types of display determines the size of each file/folder button on the screen
        /// </summary>
        public enum enuViewStyle { List, Small_icons, Medium_icons, Large_icons, _num };

        enuViewStyle eViewStyle = enuViewStyle.Medium_icons;
        /// <summary>
        /// current display size setting
        /// </summary>
        public enuViewStyle Style
        {
            get { return eViewStyle; }
            set
            {
                if (value != enuViewStyle._num)
                    if (eViewStyle != value)
                    {
                        eViewStyle = value;
                        cRegContent.IsRefreshed = false;
                        Draw();
                    }
            }
        }

        /// <summary>
        /// pointer to the Region associated with this class
        /// </summary>
        classRegion cRegContent = null;

        /// <summary>
        /// pointer to this instance used as a reference in certain function calls
        /// </summary>
        classDraw_Content cMyRef = null;

        /// <summary>
        /// instantiates an instance of this class
        /// </summary>
        /// <param name="_cRegContent">pointer to the Region associated with this instance of this class</param>
        public classDraw_Content(ref classRegion _cRegContent)
        {
            cMyRef = this;
            cRegContent = _cRegContent;
        }

        /// <summary>
        /// determines whether the CurrentDirectoryContent Region's bitmap needs to be redrawn
        /// </summary>
        public bool Refreshed
        {
            get { return cRegContent.IsRefreshed && !cRegContent.Highlight; }
        }

        /// <summary>
        /// draws the CurrentDirectoryContent Region's Bitmap before it is sampled and put to the screen 
        /// </summary>
        public void Draw()
        {
            if (Refreshed) return;

            switch (Style)
            {
                /*case enuViewStyle.Details:
                    Draw_Details();
                    break;
                    */
                default:
                    {
                        enuViewStyle eViewStyle = cRegContent.fd_Parent.cTICurrent != null
                                                                                   ? cRegContent.fd_Parent.cTICurrent.eViewStyle
                                                                                   : enuViewStyle.List;
                        Draw(eViewStyle);
                    }
                    break;
            }
        }

        /// <summary>
        /// holds the various sizes icons as they appear on the GUI-FileDialog's CurrentDirectoryContent Region
        /// </summary>
        public static List<Size> lstIconSizes = new List<Size>();

        /// <summary>
        /// list of buttons that are drawn on the CurrentDirectoryContent's bitmap (a sub-region of the entire Content Region)
        /// </summary>
        List<classButton> lstBtnOnScreen = new List<classButton>();

        /// <summary>
        /// if Region is refreshed draws the CurrentDirectoryContent Region's bitmap in the ViewStyle specified
        /// otherwise it will reset the Region's SweepAndPrune algorithm then position all the buttons in memory before calling the DRawButtonOnScreen() function
        /// </summary>
        /// <param name="eViewStyle">ViewStyle in which the CurrentDirectoryContent Region is to be drawn</param>
        void Draw(enuViewStyle eViewStyle)
        {
            if (bolDrawButtons) return;

            classTreeItem cTI_Current = cRegContent.fd_Parent.cTICurrent;
            int intWidthPreviousColumn = 0;
            if (cRegContent.IsRefreshed)
            { // no need to rebuild all the buttons
                using (Graphics g = Graphics.FromImage(cRegContent.bmp))
                {
                    for (int intButtonCounter = 0; intButtonCounter < lstBtnOnScreen.Count; intButtonCounter++)
                    {
                        classButton cBtn = lstBtnOnScreen[intButtonCounter];

                        if (!cBtn.Refreshed)
                        {
                            // draw background over previous image of button 
                            Rectangle recArea = new Rectangle(cBtn.ptDraw, cBtn.recArea.Size);
                            g.FillRectangle(cRegContent.brBackground, recArea);
                            g.DrawImage(cBtn.HighLight ? cBtn.bmpHighlight : cBtn.bmp, recArea.Location);

                            cBtn.Refreshed = true;
                        }
                    }
                }
                if (cRegContent.BlendBackground)
                    cRegContent.bmp.MakeTransparent(cRegContent.ColorBackground);
            }
            else
            { // build region's buttons without drawing bitmap
                if (cTI_Current != null)
                {
                    cTI_Current.setDirContents();

                    lstBtnOnScreen.Clear();
                    cRegContent.cSweepAndPrune.lstElements.Clear();
                    int intNumTest = 8;
                    string strTest = "Testing" + "\r\n";

                    for (int intCounter = 0; intCounter < intNumTest; intCounter++)
                        strTest += strTest;
                    double dblTestingHeight = (double)TextRenderer.MeasureText(strTest, cRegContent.font).Height;
                    double dblNumLines = (double)Math.Pow(2, intNumTest);
                    double dblButtonHeight = (double)(dblTestingHeight / dblNumLines);
                    if (lstIconSizes.Count == 0)
                    {
                        Size[] szArr =
                                { new Size(16, 16),
                                  new Size(16, 16),
                                  new Size(16, 16),
                                  new Size(50, 50),
                                  new Size(90, 90),
                                  new Size(256, 256) };
                        lstIconSizes.AddRange(szArr.ToList<Size>());
                    }
                    int intButtonHeight = (int)dblButtonHeight
                                            + (eViewStyle > enuViewStyle.Small_icons
                                                          ? lstIconSizes[(int)eViewStyle].Height
                                                          : 0);

                    // define size of bitmap
                    int intBorder = 3;
                    int intBmpHeight = cRegContent.rec.Height - cRegContent.ScrollBarWidth;
                    int intNumPerColumns = (int)Math.Floor((double)(intBmpHeight - 2 * intBorder) / (double)intButtonHeight);
                    if (intNumPerColumns < 1)
                        intNumPerColumns = 1;
                    int intBmpWidth = intBorder;
                    SolidBrush brAlt_Background = cRegContent.BlendBackground
                                                            ? new SolidBrush(Color.FromArgb((cRegContent.brBackground.Color.R + 1) % 256,
                                                                                            (cRegContent.brBackground.Color.G + 1) % 256,
                                                                                            (cRegContent.brBackground.Color.B + 1) % 256))
                                                            : cRegContent.brBackground;
                    int intColumnWidth = 0;
                    // create buttons
                    List<classButton> lstBtnColumn = new List<classButton>();
                    if (cTI_Current.lstContent == null)
                        cTI_Current.setDirContents();
                    int intColumnCounter = 0;
                    string strDir = cRegContent.fd_Parent.CurrentDirectory;
                    List<string> strSearchPatterns = cRegContent.fd_Parent.SearchPattern;
                    List<string> lstContents_SearchPattern = new List<string>();

                    lstContents_SearchPattern.AddRange(System.IO.Directory.GetDirectories(cRegContent.fd_Parent.CurrentDirectory));


                    for (int intSearchPatternCounter = 0; intSearchPatternCounter < strSearchPatterns.Count; intSearchPatternCounter++)
                    {
                        if (strSearchPatterns[intSearchPatternCounter].Length > 0)
                        {
                            try
                            {
                                lstContents_SearchPattern.AddRange(System.IO.Directory.GetFiles(strDir, strSearchPatterns[intSearchPatternCounter], SearchOption.TopDirectoryOnly).ToList<string>());
                            }
                            catch (Exception)
                            {

                            }
                        }
                    }

                    for (int intCounter = 0; intCounter < lstContents_SearchPattern.Count; intCounter++)
                    {
                        classTreeItem cTI = cRegContent.fd_Parent.TI_BinTree.Search(lstContents_SearchPattern[intCounter]);

                        if (cTI != null)
                        {
                            classSweepAndPrune.classElement cSPEle = new classSweepAndPrune.classElement();
                            classButton cBtn = new classButton();
                            cBtn.Text = cTI.strName;
                            cBtn.cTI = cTI;
                            lstBtnColumn.Add(cBtn);

                            cBtn.cParentRegion = cRegContent;
                            cSPEle.tag = (object)(cTI.eTreeItemType == classTreeItem.enuTreeItemType.directory ? classButton.enuButtonType.Directory : classButton.enuButtonType.File);
                            cSPEle.obj = (object)cBtn;
                            cBtn.obj = (object)cTI;
                            cBtn.eButtonType = cTI.eTreeItemType == classTreeItem.enuTreeItemType.directory ? classButton.enuButtonType.Directory : classButton.enuButtonType.File;

                            Size szText = TextRenderer.MeasureText(cTI.strName, cRegContent.font);

                            Size szIcon = lstIconSizes[(int)eViewStyle];
                            Size szButton = new Size();
                            switch (eViewStyle)
                            {
                                case enuViewStyle.Small_icons:
                                case enuViewStyle.List:
                                    { // icon is draw to the left of text
                                        szButton.Width = szText.Width + szIcon.Width;
                                        szButton.Height = intButtonHeight;

                                        //cBtn.bmp = new Bitmap(szButton.Width, szButton.Height);
                                        cBtn.recArea.Size = new Size(szButton.Width, szButton.Height);

                                        if (intColumnWidth < szButton.Width + intBorder)
                                            intColumnWidth = szButton.Width + intBorder;

                                        cBtn.recText.Location = new Point(szIcon.Width, 0);
                                        cBtn.recText.Size = TextRenderer.MeasureText(cBtn.Text, cRegContent.font);
                                    }
                                    break;

                                default:
                                    { // icon is drawn above the text
                                        szButton.Width = szText.Width > szIcon.Width
                                                                      ? szText.Width
                                                                      : szIcon.Width;

                                        szButton.Height = intButtonHeight;
                                        cBtn.recArea.Size = new Size(szButton.Width, szButton.Height);

                                        if (intColumnWidth < szButton.Width + intBorder)
                                            intColumnWidth = szButton.Width + intBorder;
                                        cBtn.recText.Location = new Point((cBtn.recArea.Width - szText.Width) / 2, szIcon.Height);
                                        cBtn.recText.Size = TextRenderer.MeasureText(cBtn.Text, cRegContent.font);
                                    }
                                    break;
                            }
                            if (lstBtnColumn.Count > 0 && intCounter % intNumPerColumns == 0)
                            {
                                IEnumerable<classButton> query = lstBtnColumn.OrderByDescending(button => button.recArea.Width);
                                lstBtnColumn = (List<classButton>)query.ToList<classButton>();

                                for (int intBtnCounter = 1; intBtnCounter < lstBtnColumn.Count; intBtnCounter++)
                                {
                                    classButton cBtnInList = lstBtnColumn[intBtnCounter];
                                    cBtnInList.recArea.Size = lstBtnColumn[0].recArea.Size;
                                }
                                intBmpWidth += lstBtnColumn[0].recArea.Width + intBorder;
                                intColumnWidth = 0;
                                lstBtnColumn.Clear();
                            }
                            cSPEle.obj = (object)cBtn;
                            cRegContent.cSweepAndPrune.Add(ref cSPEle);
                        }
                    }

                    // set size of buttons in last column
                    if (cRegContent.cSweepAndPrune.lstElements.Count > 0)
                    {
                        int intLastColumn = cRegContent.cSweepAndPrune.lstElements.Count - cRegContent.cSweepAndPrune.lstElements.Count % intNumPerColumns;
                        if (intLastColumn == cRegContent.cSweepAndPrune.lstElements.Count)
                        {
                            if (cRegContent.cSweepAndPrune.lstElements.Count > intNumPerColumns)
                                intLastColumn = cRegContent.cSweepAndPrune.lstElements.Count - intNumPerColumns;
                            else
                                intLastColumn = 0;
                        }
                        List<classButton> lstButtonLastColumn = new List<classButton>();
                        for (int intBtnCounter = intLastColumn; intBtnCounter < cRegContent.cSweepAndPrune.lstElements.Count; intBtnCounter++)
                        {
                            classButton cBtnInLastColumn = (classButton)cRegContent.cSweepAndPrune.lstElements[intBtnCounter].obj;
                            lstButtonLastColumn.Add(cBtnInLastColumn);
                        }
                        IEnumerable<classButton> query = lstButtonLastColumn.OrderByDescending(button => button.recArea.Width);
                        lstButtonLastColumn = (List<classButton>)query.ToList<classButton>();

                        for (int intButtonInListCounter = 1; intButtonInListCounter < lstButtonLastColumn.Count; intButtonInListCounter++)
                        {
                            classButton cBtnInLastColumn = lstButtonLastColumn[intButtonInListCounter];
                            cBtnInLastColumn.recArea.Size = lstButtonLastColumn[0].recArea.Size;
                        }

                        intBmpWidth += lstButtonLastColumn[0].recArea.Width + intBorder;
                    }

                    if (intBmpWidth < cRegContent.rec.Width)
                        intBmpWidth = cRegContent.rec.Width;
                    if (intBmpHeight < cRegContent.rec.Height)
                        intBmpHeight = cRegContent.rec.Height;
                    cRegContent.szBmp = new Size(intBmpWidth, intBmpHeight);

                    // draw bitmap & position buttons

                    Point ptTL = new Point(intBorder, intBorder);

                    for (int intCounter = 0; intCounter < cRegContent.cSweepAndPrune.lstElements.Count; intCounter++)
                    {
                        classSweepAndPrune.classElement cSW_Ele = cRegContent.cSweepAndPrune.lstElements[intCounter];

                        classButton cBtn = (classButton)cSW_Ele.obj;

                        cBtn.recArea.Location
                            = cSW_Ele.rec.Location
                            = ptTL;
                        cSW_Ele.rec.Size = cBtn.recArea.Size;
                        if ((intCounter > 0 || intNumPerColumns == 1) && (intCounter + 1) % intNumPerColumns == 0)
                        {
                            // start new column
                            if (true || intColumnCounter == 0)
                            {
                                ptTL = new Point(cBtn.recArea.Right + intBorder, intBorder);
                            }
                            else
                            {
                                ptTL = new Point(ptTL.X + intWidthPreviousColumn + intBorder, intBorder);
                            }
                            intWidthPreviousColumn = cBtn.recArea.Width;
                            intColumnCounter++;

                        }
                        else
                        {
                            // move down to next file
                            ptTL = new Point(ptTL.X, ptTL.Y + cBtn.recArea.Height);
                        }
                    }
                    cRegContent.bolRecVisible_OffSet_Valid = false;
                    DrawButtonsOnScreen(eViewStyle);
                    cRegContent.IsRefreshed = true;
                }
                else
                {  // cTI_Current == null
                    try
                    {

                        cRegContent.szBmp = cRegContent.rec.Size;
                    }
                    catch (Exception eWhyTheFuck)
                    {
                        System.Diagnostics.Debug.Print(eWhyTheFuck.Message);
                    }
                    cRegContent.bmp = new Bitmap(cRegContent.szBmp.Width, cRegContent.szBmp.Height);
                    using (Graphics g = Graphics.FromImage(cRegContent.bmp))
                    {
                        g.FillRectangle(cRegContent.brBackground, 0, 0, cRegContent.bmp.Width, cRegContent.bmp.Height);
                    }
                    cRegContent.ptRecVisible_Offset = new Point();
                }
            }
        }

        /// <summary>
        /// used to exit DrawButtonsOnScreen() if DrawButtonsOnScreen() is already being executed
        /// </summary>
        bool bolDrawButtons = false;

        /// <summary>
        /// determines which buttons are on the sub-Region being sampled to the Screen then Draws them to the Region's bitmap
        /// </summary>
        /// <param name="eViewStyle">style in which the Region's Buttons are to be drawn</param>
        public void DrawButtonsOnScreen(enuViewStyle eViewStyle)
        {
            if (bolDrawButtons) return;

            Size szRec_Plus = new Size(cRegContent.rec.Width / 2, cRegContent.rec.Height / 2);
            if (cRegContent.bolRecVisible_OffSet_Valid
                && cRegContent.ptRecVisible_Offset.X > 0 && cRegContent.ptRecVisible_Offset.X < 1.5 * szRec_Plus.Width
                && cRegContent.ptRecVisible_Offset.Y > 0 && cRegContent.ptRecVisible_Offset.Y < 1.5 * szRec_Plus.Height) return;


            cRegContent.bolRecVisible_OffSet_Valid = true;

            bolDrawButtons = true;
            Rectangle recVisible_Plus = new Rectangle(cRegContent.recVisible.Left - szRec_Plus.Width,
                                                      cRegContent.recVisible.Top - szRec_Plus.Height,
                                                      cRegContent.recVisible.Width + 2 * szRec_Plus.Width,
                                                      cRegContent.recVisible.Height + 2 * szRec_Plus.Height);

            List<classSweepAndPrune.classElement> lstSweepPruneSearchResults = cRegContent.cSweepAndPrune.Search(recVisible_Plus);

            cRegContent.bmp = new Bitmap(recVisible_Plus.Width, recVisible_Plus.Height);
            cRegContent.ptRecVisible_Offset = new Point(szRec_Plus.Width, szRec_Plus.Height);

            List<classButton> lstBtn_New = new List<classButton>();
            using (Graphics gReg = Graphics.FromImage(cRegContent.bmp))
            {
                gReg.FillRectangle(cRegContent.brBackground, 0, 0, recVisible_Plus.Width, recVisible_Plus.Height);

                for (int intCounter = 0; intCounter < lstSweepPruneSearchResults.Count; intCounter++)
                {
                    classSweepAndPrune.classElement cSP_Ele = lstSweepPruneSearchResults[intCounter];
                    classButton cBtn = (classButton)cSP_Ele.obj;

                    lstBtn_New.Add(cBtn);
                    cBtn.ptDraw = new Point(cBtn.recArea.Left - cRegContent.recVisible.Left + cRegContent.ptRecVisible_Offset.X,
                                            cBtn.recArea.Top - cRegContent.recVisible.Top + cRegContent.ptRecVisible_Offset.Y);
                    gReg.DrawImage(cBtn.bmp, cBtn.ptDraw);
                }

                // int intRadius = 3;
                //gReg.DrawEllipse(Pens.Red, new RectangleF(cRegContent.ptRecVisible_Offset.X - intRadius, cRegContent.ptRecVisible_Offset.Y - intRadius, 2 * intRadius, 2 * intRadius));
            }

            for (int intCounter = 0; intCounter < lstBtnOnScreen.Count; intCounter++)
            {
                classButton cBtn = lstBtnOnScreen[intCounter];
                if (!lstBtn_New.Contains(cBtn))
                {
                    cBtn.bmpHighlight.Dispose();
                    cBtn.bmp.Dispose();
                    cBtn.bmp
                        = cBtn.bmpHighlight
                        = null;
                }
            }
            lstBtnOnScreen = lstBtn_New;

            cRegContent.fd_Parent.DrawScreen();
            bolDrawButtons = false;
        }
    }

    /// <summary>
    /// class used to draw the Directory Tree
    /// </summary>
    public class classDraw_DirTree
    {
        /// <summary>
        /// bitmap of the idle expanded button icon
        /// </summary>
        static Bitmap bmpExpanded = null;
        /// <summary>
        /// bitmap of the idle collapsed button icon
        /// </summary>
        static Bitmap bmpCollapsed = null;
        /// <summary>
        /// bitmap of the highlighted expanded button icon
        /// </summary>
        static Bitmap bmpExpanded_Highlight = null;
        /// <summary>
        /// bitmap of the highlight-collapsed button icon
        /// </summary>
        static Bitmap bmpCollapsed_Highlight = null;

        /// <summary>
        /// number of pixels between each column of the Directory Tree
        /// </summary>
        public int intIndentStepSize = 15;

        /// <summary>
        /// number of pixels between each row of the Directory Tree
        /// </summary>
        int intVIndent = 2;

        /// <summary>
        /// BottomRight corner : point used to measure the overall size of the DirectoryTree region in memory while Tree Items are cumulatively added to the Tree from top - down
        /// </summary>
        Point ptBR = new Point();

        /// <summary>
        /// pointer to the Region associated with this class
        /// </summary>
        classRegion cRegDirTree = null;

        bool bolRefreshed = false;
        /// <summary>
        /// determines whether the DirectoryTree region's sub-region bitmap needs to be redrawn
        /// </summary>
        public bool Refreshed
        {
            get { return bolRefreshed; }
            set
            {
                bolRefreshed = value;
                if (!bolRefreshed)
                    bmpCollapsed = null;
            }
        }

        /// <summary>
        /// pointer to this instance of this class used as a reference to itself in certain function calls
        /// </summary>
        classDraw_DirTree cMyRef = null;

        /// <summary>
        /// instantiates an instance of this class
        /// </summary>
        /// <param name="RegDirTree">reference pointer to the DirectoryTree Region associated with this class</param>
        public classDraw_DirTree(ref classRegion RegDirTree)
        {
            cRegDirTree = RegDirTree;
            cMyRef = this;
        }

        /// <summary>
        /// brush used to draw the DirectoryTree's background
        /// </summary>
        SolidBrush brBackground { get { return cRegDirTree.brBackground; ; } }
        /// <summary>
        /// brush used to draw the DirectoryTree's foreground
        /// </summary>
        SolidBrush brForeground { get { return cRegDirTree.brForeground; } }
        /// <summary>
        /// pen used to draw the Directory Tree's foreground
        /// </summary>
        Pen pForeground { get { return cRegDirTree.pForeground; } }
        /// <summary>
        /// pen used to draw the Directory Tree's background
        /// </summary>
        Pen pBackground { get { return cRegDirTree.pBackground; } }

        /// <summary>
        /// list of buttons currently drawn on the DirectoryTree Region's bitmap
        /// </summary>
        List<classButton> lstBtnOnScreen = new List<classButton>();

        /// <summary>
        /// static counter used to determine whether buttons associated with DirectoryTree TreeItems are valid and have the current counter value set
        /// </summary>
        public static uint untDirTreeButton_State_Counter = 0;
        
        /// <summary>
        /// refreshes the DirectoryTree Region's buttons (highlight changes) if Region is Refreshed already
        /// or rebuilds the Directory Tree after expand/collapse user-changes - then draws all buttons with DrawButtonToScreen()
        /// </summary>
        /// <param name="cTI_Root"></param>
        public void Draw(ref classTreeItem cTI_Root)
        {
            if (cTI_Root == null) return;

            if (Refreshed)
            {
                using (Graphics g = Graphics.FromImage(cRegDirTree.bmp))
                {
                    for (int intButtonCounter = 0; intButtonCounter < lstBtnOnScreen.Count; intButtonCounter++)
                    {
                        classButton cBtn = lstBtnOnScreen[intButtonCounter];
                        if (!cBtn.Refreshed)
                        {
                            Bitmap bmpButton = cBtn.HighLight || cBtn.Toggled ? cBtn.bmpHighlight : cBtn.bmp;
                            g.DrawImage(bmpButton, cBtn.ptDraw); // cBtn.recArea.Location);
                            cBtn.Refreshed = true;
                        }
                    }
                }
            }
            else
            {
                lstBtnOnScreen.Clear();
                cRegDirTree.cSweepAndPrune.lstElements.Clear();
                ptBR = new Point(1, 1);

                Draw_Recurse(ref cTI_Root);

                bool bolHBar = ptBR.X > cRegDirTree.rec.Width;
                bool bolVBar = ptBR.Y > cRegDirTree.rec.Height;
                int intWidthNeeded = cRegDirTree.rec.Width - (bolVBar ? cRegDirTree.ScrollBarWidth : 0);
                if (ptBR.X < intWidthNeeded)
                    ptBR.X = intWidthNeeded;
                int intHeightNeeded = cRegDirTree.rec.Height - (bolHBar ? cRegDirTree.ScrollBarWidth : 0);
                if (ptBR.Y < intHeightNeeded)
                    ptBR.Y = intHeightNeeded;

                if (cRegDirTree.ScrollBarV_Shown)
                {
                    if (cRegDirTree.cScrollBarV != null)
                    {
                        if (cRegDirTree.fd_Parent.cTICurrent != null
                            && cRegDirTree.fd_Parent.cTICurrent.btn != null)
                        {
                            cRegDirTree.cScrollBarV.Value = (double)cRegDirTree.fd_Parent.cTICurrent.btn.recArea.Top / (double)(ptBR.Y - cRegDirTree.rec.Height);
                        }
                    }
                }

                cRegDirTree.szBmp = new Size(ptBR.X, ptBR.Y);
                cRegDirTree.bolRecVisible_OffSet_Valid = false;

                DrawButtonsOnScreen();
                Refreshed = true;
            }
        }

        /// <summary>
        /// rebuilds the button content of the DirectoryTree Region to reflect most recent User made changes to the expand/collapse buttons
        /// </summary>
        /// <param name="cTI">reference to the root Tree-Item of this region</param>
        void Draw_Recurse(ref classTreeItem cTI)
        {
            Size sz = TextRenderer.MeasureText(cTI.strName, cRegDirTree.font);
            Point pt = new Point((1 + cTI.intNumParents) * intIndentStepSize, ptBR.Y);
            Rectangle rec = new Rectangle(pt, sz);

            // create expand button
            if (cTI.eTreeItemType == classTreeItem.enuTreeItemType.directory)
            {
                if (bmpCollapsed == null)
                    DrawExpandedCollapsedBitmaps();
                Point ptExpand = new Point(pt.X - (cTI.Expanded ? bmpExpanded.Width : bmpCollapsed.Width), pt.Y + (sz.Height - (cTI.Expanded ? bmpExpanded.Height : bmpCollapsed.Height)) / 2);

                object objTI_Expand = (object)cTI;
                classButton cBtn_Expand = new classButton();
                cBtn_Expand.cParentRegion = cRegDirTree;
                cBtn_Expand.recArea = new Rectangle(ptExpand, bmpCollapsed.Size);
                cBtn_Expand.bmp = cTI.Expanded ? bmpExpanded : bmpCollapsed;
                cBtn_Expand.bmpHighlight = cTI.Expanded ? bmpExpanded_Highlight : bmpCollapsed_Highlight;
                cBtn_Expand.eButtonType = classButton.enuButtonType.ExpandCollapse;
                cBtn_Expand.obj = objTI_Expand;
                cBtn_Expand.Text = "Expand_" + cTI.strName;

                classSweepAndPrune.classElement cSWEle_Expand = new classSweepAndPrune.classElement();
                cSWEle_Expand.obj = (object)cBtn_Expand;
                cSWEle_Expand.rec = cBtn_Expand.recArea;
                cSWEle_Expand.tag = (object)classButton.enuButtonType.ExpandCollapse;
                cRegDirTree.cSweepAndPrune.Add(ref cSWEle_Expand);
            }

            // create button
            object objTI = (object)cTI;
            classButton btnNew = cRegDirTree.Button_Add(rec, ref objTI);
            btnNew.Text = cTI.strName;
            btnNew.bmp = new Bitmap(sz.Width, sz.Height);
            btnNew.eButtonType = cTI.eTreeItemType == classTreeItem.enuTreeItemType.directory ? classButton.enuButtonType.Directory : classButton.enuButtonType.File;
            btnNew.cTI = cTI;
            using (Graphics gBtn = Graphics.FromImage(btnNew.bmp))
            {
                gBtn.FillRectangle(brBackground, 0, 0, btnNew.bmp.Width, btnNew.bmp.Height);
                gBtn.DrawString(cTI.strName, cRegDirTree.font, brForeground, new Point(0, 0));
            }

            btnNew.bmpHighlight = new Bitmap(sz.Width, sz.Height);
            using (Graphics gBtn = Graphics.FromImage(btnNew.bmpHighlight))
            {
                gBtn.FillRectangle(brForeground, 0, 0, btnNew.bmpHighlight.Width, btnNew.bmpHighlight.Height);
                gBtn.DrawString(cTI.strName, cRegDirTree.font, brBackground, new Point(0, 0));
            }

            btnNew.Toggled = string.Compare(cTI.strPath.ToUpper().Trim(), cRegDirTree.fd_Parent.CurrentDirectory.ToUpper().Trim()) == 0;


            cTI.btn = btnNew;

            if (rec.Right > ptBR.X)
                ptBR.X = rec.Right;
            ptBR.Y = rec.Bottom + intVIndent;

            classSweepAndPrune.classElement cSPEle = new classSweepAndPrune.classElement();
            cSPEle.obj = (object)btnNew;
            cSPEle.rec = new Rectangle(pt, btnNew.bmp.Size);
            cSPEle.tag = (object)btnNew.eButtonType;
            cRegDirTree.cSweepAndPrune.Add(ref cSPEle);

            if (cTI.Expanded)
            {
                if (cTI.lstContent == null)
                    cTI.setDirContents();
                for (int intCounter = 0; intCounter < cTI.lstContent.Count; intCounter++)
                {
                    classTreeItem cTISub = cTI.lstContent[intCounter];
                    if (cTISub.eTreeItemType == classTreeItem.enuTreeItemType.directory)
                        Draw_Recurse(ref cTISub);
                }
            }
        }

        /// <summary>
        /// used to avoid execution of the DrawButtonsOnScreen function when that function is already being executed
        /// </summary>
        bool bolDrawButtons = false;

        /// <summary>
        /// redraws the DirectoryTree's bitmap after the Region has either been rebuilt or the Scroll bar has moved visible area beyond what is already drawn
        /// </summary>
        public void DrawButtonsOnScreen()
        {
            if (bolDrawButtons) return;
            untDirTreeButton_State_Counter++;

            Size szRec_Plus = new Size(cRegDirTree.rec.Width / 2, cRegDirTree.rec.Height / 2);
            if (cRegDirTree.bolRecVisible_OffSet_Valid
                && cRegDirTree.ptRecVisible_Offset.X > 0 && cRegDirTree.ptRecVisible_Offset.X < 1.5 * szRec_Plus.Width
                && cRegDirTree.ptRecVisible_Offset.Y > 0 && cRegDirTree.ptRecVisible_Offset.Y < 1.5 * szRec_Plus.Height) return;


            cRegDirTree.bolRecVisible_OffSet_Valid = true;

            bolDrawButtons = true;
            Rectangle recVisible_Plus = new Rectangle(cRegDirTree.recVisible.Left - szRec_Plus.Width,
                                                      cRegDirTree.recVisible.Top - szRec_Plus.Height,
                                                      cRegDirTree.recVisible.Width + 2 * szRec_Plus.Width,
                                                      cRegDirTree.recVisible.Height + 2 * szRec_Plus.Height);

            List<classSweepAndPrune.classElement> lstSweepPruneSearchResults = cRegDirTree.cSweepAndPrune.Search(recVisible_Plus);

            cRegDirTree.bmp = new Bitmap(recVisible_Plus.Width, recVisible_Plus.Height);
            cRegDirTree.ptRecVisible_Offset = new Point(szRec_Plus.Width, szRec_Plus.Height);

            List<classButton> lstBtn_New = new List<classButton>();
            using (Graphics gReg = Graphics.FromImage(cRegDirTree.bmp))
            {
                gReg.FillRectangle(cRegDirTree.brBackground, 0, 0, recVisible_Plus.Width, recVisible_Plus.Height);

                for (int intCounter = 0; intCounter < lstSweepPruneSearchResults.Count; intCounter++)
                {
                    classSweepAndPrune.classElement cSP_Ele = lstSweepPruneSearchResults[intCounter];
                    classButton cBtn = (classButton)cSP_Ele.obj;
                    cBtn.DirTreeState = untDirTreeButton_State_Counter;

                    lstBtn_New.Add(cBtn);
                    cBtn.ptDraw = new Point(cBtn.recArea.Left - cRegDirTree.recVisible.Left + cRegDirTree.ptRecVisible_Offset.X,
                                            cBtn.recArea.Top - cRegDirTree.recVisible.Top + cRegDirTree.ptRecVisible_Offset.Y);
                    cRegDirTree.fd_Parent.TI_BinTree.Insert(ref cBtn.cTI);
                    Bitmap bmpButton = cBtn.Toggled || cBtn.HighLight ? cBtn.bmpHighlight : cBtn.bmp;
                    gReg.DrawImage(bmpButton, cBtn.ptDraw);
                }

                int intRadius = 3;
                gReg.DrawEllipse(Pens.Red, new RectangleF(cRegDirTree.ptRecVisible_Offset.X - intRadius, cRegDirTree.ptRecVisible_Offset.Y - intRadius, 2 * intRadius, 2 * intRadius));
            }

            lstBtnOnScreen = lstBtn_New;

            cRegDirTree.fd_Parent.DrawScreen();
            bolDrawButtons = false;
        }

        /// <summary>
        /// is used to draw the Expanded/Collapsed button icons at program app's launch
        /// </summary>
        void DrawExpandedCollapsedBitmaps()
        {
            Size sz = new Size(11, 8);
            bmpExpanded = new Bitmap(sz.Width, sz.Height);
            Point[] ptExpanded = { new Point(1, 1), new Point(5, 6), new Point(9, 1) };
            Pen pF = new Pen(pForeground.Color, 2);
            Pen pB = new Pen(pBackground.Color, 2);
            using (Graphics g = Graphics.FromImage(bmpExpanded))
            {
                g.FillRectangle(brBackground, 0, 0, bmpExpanded.Width, bmpExpanded.Height);
                g.DrawLine(pF, ptExpanded[0], ptExpanded[1]);
                g.DrawLine(pF, ptExpanded[1], ptExpanded[2]);
            }

            bmpExpanded_Highlight = new Bitmap(sz.Width, sz.Height);
            using (Graphics g = Graphics.FromImage(bmpExpanded_Highlight))
            {
                g.FillRectangle(brForeground, 0, 0, bmpExpanded.Width, bmpExpanded.Height);
                g.DrawLine(pB, ptExpanded[0], ptExpanded[1]);
                g.DrawLine(pB, ptExpanded[1], ptExpanded[2]);
            }

            Point[] ptCollapsed = { new Point(1, 1), new Point(5, 5), new Point(1, 9) };
            sz = new Size(8, 11);
            bmpCollapsed = new Bitmap(sz.Width, sz.Height);
            using (Graphics g = Graphics.FromImage(bmpCollapsed))
            {
                g.FillRectangle(brBackground, 0, 0, bmpCollapsed.Width, bmpCollapsed.Height);
                g.DrawLine(pF, ptCollapsed[0], ptCollapsed[1]);
                g.DrawLine(pF, ptCollapsed[1], ptCollapsed[2]);
            }

            bmpCollapsed_Highlight = new Bitmap(sz.Width, sz.Height);
            using (Graphics g = Graphics.FromImage(bmpCollapsed_Highlight))
            {
                g.FillRectangle(brForeground, 0, 0, bmpCollapsed_Highlight.Width, bmpCollapsed_Highlight.Height);
                g.DrawLine(pB, ptCollapsed[0], ptCollapsed[1]);
                g.DrawLine(pB, ptCollapsed[1], ptCollapsed[2]);
            }
        }
    }

    /// <summary>
    /// class used to define the buttons that interact with the user on screen
    /// </summary>
    public class classButton
    {
        /// <summary>
        /// pointer to the Region with this button belongs to
        /// </summary>
        public classRegion cParentRegion = null;

        /// <summary>
        /// used for debugging purposes
        /// </summary>
        static int intIDCounter = 0;

        /// <summary>
        /// used for debugging purposes
        /// </summary>
        public int intID = intIDCounter++;

        /// <summary>
        /// used to be certain the existing buttons are up to date
        /// </summary>
        uint _untDirTreeState = 0;
        public uint DirTreeState
        {
            get { return _untDirTreeState; }
            set { _untDirTreeState = value; }
        }

        /// <summary>
        /// instantiates an instance of this class
        /// </summary>
        public classButton()
        {

        }

        static Bitmap _bmpIcon_FileFolder = null;

        /// <summary>
        /// bitmap image of the FileFolder icon - drawn during runtime the first time it is requested
        /// </summary>
        static Bitmap bmpIcon_FileFolder
        {
            get
            {
                if (_bmpIcon_FileFolder == null)
                {
                    _bmpIcon_FileFolder = new Bitmap(50, 50);
                    Color clrTransparent = Color.Green;
                    using (Graphics g = Graphics.FromImage(_bmpIcon_FileFolder))
                    {
                        g.FillRectangle(new SolidBrush(clrTransparent), 0, 0, 49, 49);

                        Point[] ptBack = { new Point(9, 0), new Point(39, 0), new Point(39, 25), new Point(42, 28), new Point(42, 41), new Point(9, 41) };
                        g.FillPolygon(new SolidBrush(Color.FromArgb(252, 222, 127)), ptBack);

                        Point[] ptFront = { new Point(9, 0), new Point(21, 9), new Point(21, 49), new Point(9, 41) };
                        g.FillPolygon(new SolidBrush(Color.FromArgb(255, 233, 161)), ptFront);
                    }

                    _bmpIcon_FileFolder.MakeTransparent(_bmpIcon_FileFolder.GetPixel(0, 0));
                }
                return _bmpIcon_FileFolder;
            }
        }

        /// <summary>
        /// pointer to the bitmap used as an icon for the various file extension types
        /// </summary>
        static Bitmap bmpFile = null;

        /// <summary>
        /// string that defines the valid image file extension types - used when determining whether the file's image is to be used as an icon in the CurrentDirectoryContent's file list
        /// </summary>
        static string strValidImageFileExtensions = ".JPG.PNG.GIF.IMG.BMP.";

        /// <summary>
        /// list of types of buttons
        /// </summary>
        public enum enuButtonType { File, Directory, ExpandCollapse, ScrollBar_V, ScrollBar_H, UserInput, _num };

        /// <summary>
        /// type of button this instance is
        /// </summary>
        public enuButtonType eButtonType = enuButtonType.Directory;

        /// <summary>
        /// rectangular region this button occupies in it's parent Region (not necessary location on bitmap for regContent & regDirTree but rather the locations in memory)
        /// </summary>
        public Rectangle recArea = new Rectangle();
        
        /// <summary>
        /// used by regContent/regDirTree to determine which portion of the Region's sub-Region Bitmap is to be sampled and put to the screen - is a function of ScrollBar and recVisible
        /// </summary>
        public Point ptDraw = new Point();
        
        /// <summary>
        /// object attached to this button
        /// </summary>
        public object obj = null;

        /// <summary>
        /// retrieves the MS-Windows Icon associated with the specfied file 
        /// searches the BinaryTree to retrieve Icon associated with the file's extension
        /// or finds the Icon associated with that Extension through the MS-Windows OS then inserts it into the Binary Tree for future retrieval
        /// </summary>
        /// <param name="strPath">name of the file specified</param>
        /// <returns>an icon associated with the specified file name</returns>
        Icon icon_File(string strPath)
        {
            string strExtension = getExtensionFromPath(strPath);
            Icon icoRetVal = classFileIcons.Search(strExtension);

            if (icoRetVal == null)
            {
                try
                {
                    icoRetVal = System.Drawing.Icon.ExtractAssociatedIcon(strPath);
                }
                catch (Exception)
                {
                }

                if (icoRetVal != null)
                {
                    classFileIcons.Insert(cTI.fileInfo.Extension, ref icoRetVal);
                }
                else
                    ;
            }

            return icoRetVal;
        }

        /// <summary>
        /// strips the file's extension from its full path-name
        /// </summary>
        /// <param name="strPath">path of the file</param>
        /// <returns>the extension of the file sent as input parameter</returns>
        string getExtensionFromPath(string strPath)
        {
            int intExtension = strPath.LastIndexOf(".");
            if (intExtension >= 0)
            {
                string strRetVal = strPath.Substring(intExtension + 1);
                return strRetVal;
            }
            return "";
        }

        Bitmap _bmp = null;
        /// <summary>
        /// idle image of this instance of the classButton depending on the Tree-Item associated with this button
        /// </summary>
        public Bitmap bmp
        {
            get
            {
                if (cParentRegion == null) return _bmp;
                switch (cParentRegion.Region)
                {
                    case FileDialog_GUI.enuRegions.ContentCurrentDirectory:
                        {
                            if (_bmp == null)
                            {
                                classDraw_Content.enuViewStyle eViewStyle = (cParentRegion.fd_Parent.cTICurrent != null
                                                                                                                ? cParentRegion.fd_Parent.cTICurrent.eViewStyle
                                                                                                                : classDraw_Content.enuViewStyle.List);
                                Size szIcon = classDraw_Content.lstIconSizes[(int)eViewStyle];
                                Point ptTextLocation = new Point(recText.Left,
                                                                 recText.Top);

                                switch (eViewStyle)
                                {
                                    case classDraw_Content.enuViewStyle.Small_icons:
                                    case classDraw_Content.enuViewStyle.List:
                                        { // icon is draw to the left of text
                                            switch (cTI.eTreeItemType)
                                            {
                                                case classTreeItem.enuTreeItemType.directory:
                                                    {
                                                        if (_bmp == null)
                                                        {
                                                            _bmp = new Bitmap(recArea.Width, recArea.Height);
                                                            Bitmap bmpIcon = bmpIcon_FileFolder;
                                                            try
                                                            {
                                                                Rectangle recSource = new Rectangle(0, 0, bmpIcon.Width, bmpIcon.Height);
                                                                Rectangle recDest = new Rectangle(0, 0, szIcon.Width, szIcon.Height);
                                                                using (Graphics g = Graphics.FromImage(_bmp))
                                                                {
                                                                    g.FillRectangle(cParentRegion.brBackground, new RectangleF(0, 0, recArea.Width, recArea.Height));
                                                                    g.DrawImage(bmpIcon, recDest, recSource, GraphicsUnit.Pixel);
                                                                    g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                }
                                                            }
                                                            catch (Exception)
                                                            {


                                                            }
                                                        }
                                                    }
                                                    break;

                                                case classTreeItem.enuTreeItemType.file:
                                                    {
                                                        if (_bmp == null)
                                                        {
                                                            _bmp = new Bitmap(recArea.Width, recArea.Height);
                                                            using (Graphics g = Graphics.FromImage(_bmp))
                                                            {
                                                                g.FillRectangle(cParentRegion.brBackground, new RectangleF(0, 0, _bmp.Width, _bmp.Height));
                                                                Icon icoFile = classFileIcons.Search(cTI.fileInfo.Extension);
                                                                if (icoFile == null)
                                                                {
                                                                    try
                                                                    {
                                                                        icoFile = System.Drawing.Icon.ExtractAssociatedIcon(cTI.fileInfo.DirectoryName);
                                                                    }
                                                                    catch (Exception)
                                                                    {
                                                                    }
                                                                }

                                                                if (icoFile != null)
                                                                {
                                                                    classFileIcons.Insert(cTI.fileInfo.Extension, ref icoFile);
                                                                    bmpFile = (Bitmap)icoFile.ToBitmap();

                                                                    if (bmpFile != null)
                                                                    {
                                                                        g.FillRectangle(cParentRegion.brBackground, new RectangleF(0, 0, recArea.Width, recArea.Height));
                                                                        double dblAspectRatio = (double)bmpFile.Height / (double)bmpFile.Width;
                                                                        if (dblAspectRatio > 1)
                                                                        { // height is limiting factor
                                                                            Rectangle recSource = new Rectangle(0, 0, bmpFile.Width, bmpFile.Height);
                                                                            Rectangle recDest = new Rectangle(0, 0, (int)((double)szIcon.Height / dblAspectRatio), szIcon.Height);
                                                                            g.DrawImage(bmpFile, recDest, recSource, GraphicsUnit.Pixel);
                                                                            g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                        }
                                                                        else
                                                                        { // width is limiting factor
                                                                            Rectangle recSource = new Rectangle(0, 0, bmpFile.Width, bmpFile.Height);
                                                                            Rectangle recDest = new Rectangle(0, 0, szIcon.Width, (int)((double)szIcon.Width * dblAspectRatio));
                                                                            g.DrawImage(bmpFile, recDest, recSource, GraphicsUnit.Pixel);
                                                                            g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                        }
                                                                        bmpFile = null;
                                                                        g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                    }
                                                                }
                                                                else
                                                                    ;
                                                            }
                                                        }
                                                    }
                                                    break;
                                            }
                                        }
                                        break;

                                    default:
                                        {
                                            switch (cTI.eTreeItemType)
                                            {
                                                case classTreeItem.enuTreeItemType.directory:
                                                    {
                                                        if (_bmp == null)
                                                        {
                                                            _bmp = new Bitmap(recArea.Width, recArea.Height);
                                                            Bitmap bmpIcon = bmpIcon_FileFolder;
                                                            Rectangle recSource = new Rectangle(0, 0, bmpIcon.Width, bmpIcon.Height);
                                                            Rectangle recDest = new Rectangle(0, 0, szIcon.Width, szIcon.Height);
                                                            using (Graphics g = Graphics.FromImage(_bmp))
                                                            {
                                                                g.FillRectangle(cParentRegion.brBackground, new RectangleF(0, 0, recArea.Width, recArea.Height));
                                                                g.DrawImage(bmpIcon, recDest, recSource, GraphicsUnit.Pixel);
                                                                g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                            }
                                                        }
                                                    }
                                                    break;

                                                case classTreeItem.enuTreeItemType.file:
                                                    {
                                                        if (_bmp == null)
                                                        {
                                                            string strExtension = cTI.fileInfo.Extension.ToUpper();

                                                            _bmp = new Bitmap(recArea.Width, recArea.Height);

                                                            using (Graphics g = Graphics.FromImage(_bmp))
                                                            {
                                                                g.FillRectangle(cParentRegion.brBackground, new RectangleF(0, 0, recArea.Width, recArea.Height));
                                                                if (strValidImageFileExtensions.Contains(strExtension))
                                                                { // this is an image file
                                                                    using (MemoryStream s = new MemoryStream(File.ReadAllBytes(cTI.strPath)))
                                                                    {
                                                                        try
                                                                        {
                                                                            bmpFile = (Bitmap)Bitmap.FromStream(s);

                                                                            double dblAspectRatio = (double)bmpFile.Height / (double)bmpFile.Width;
                                                                            if (dblAspectRatio > 1)
                                                                            { // height is limiting factor
                                                                                Rectangle recSource = new Rectangle(0, 0, bmpFile.Width, bmpFile.Height);
                                                                                Rectangle recDest = new Rectangle(0, 0, (int)((double)szIcon.Height / dblAspectRatio), szIcon.Height);
                                                                                g.DrawImage(bmpFile, recDest, recSource, GraphicsUnit.Pixel);
                                                                                g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                            }
                                                                            else
                                                                            { // width is limiting factor
                                                                                Rectangle recSource = new Rectangle(0, 0, bmpFile.Width, bmpFile.Height);
                                                                                Rectangle recDest = new Rectangle(0, 0, szIcon.Width, (int)((double)szIcon.Width * dblAspectRatio));
                                                                                g.DrawImage(bmpFile, recDest, recSource, GraphicsUnit.Pixel);
                                                                                g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                            }
                                                                        }
                                                                        catch (Exception)
                                                                        {

                                                                        }
                                                                    }
                                                                    bmpFile = null;
                                                                }
                                                                else
                                                                {
                                                                    Icon icoFile = classFileIcons.Search(cTI.fileInfo.Extension);
                                                                    if (icoFile == null)
                                                                        icoFile = icon_File(cTI.strPath);

                                                                    if (icoFile != null)
                                                                    {
                                                                        bmpFile = icoFile.ToBitmap();

                                                                        double dblAspectRatio = (double)bmpFile.Height / (double)bmpFile.Width;
                                                                        if (dblAspectRatio > 1)
                                                                        { // height is limiting factor
                                                                            Rectangle recSource = new Rectangle(0, 0, bmpFile.Width, bmpFile.Height);
                                                                            Rectangle recDest = new Rectangle(0, 0, (int)((double)szIcon.Height / dblAspectRatio), szIcon.Height);
                                                                            g.DrawImage(bmpFile, recDest, recSource, GraphicsUnit.Pixel);
                                                                            g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                        }
                                                                        else
                                                                        { // width is limiting factor
                                                                            Rectangle recSource = new Rectangle(0, 0, bmpFile.Width, bmpFile.Height);
                                                                            Rectangle recDest = new Rectangle(0, 0, szIcon.Width, (int)((double)szIcon.Width * dblAspectRatio));
                                                                            g.DrawImage(bmpFile, recDest, recSource, GraphicsUnit.Pixel);
                                                                            g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                        }
                                                                        bmpFile = null;
                                                                        g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                    break;
                                            }
                                        }
                                        break;
                                }

                                return _bmp;
                            }
                        }
                        break;


                    case FileDialog_GUI.enuRegions.DirTree:
                        {
                            if (_bmp == null)
                            {
                                Point ptTextLocation = new Point(recText.Left,
                                                                 recText.Top);

                                _bmp = new Bitmap(recArea.Width, recArea.Height);
                                using (Graphics g = Graphics.FromImage(_bmp))
                                {
                                    g.FillRectangle(cParentRegion.brBackground, new RectangleF(0, 0, recArea.Width, recArea.Height));
                                    g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brForeground, ptTextLocation);
                                }

                                _bmpHighlight = new Bitmap(recArea.Width, recArea.Height);
                                using (Graphics g = Graphics.FromImage(_bmpHighlight))
                                {
                                    g.FillRectangle(cParentRegion.brForeground, new RectangleF(0, 0, recArea.Width, recArea.Height));
                                    g.DrawString(cTI.strName, cParentRegion.font, cParentRegion.brBackground, ptTextLocation);
                                }

                                return _bmp;
                            }
                        }
                        break;

                    default:
                        break;
                }
                if (_bmp != null && _bmp.PixelFormat == System.Drawing.Imaging.PixelFormat.DontCare)
                    ;

                return _bmp;

            }
            set { _bmp = value; }
        }

        Bitmap _bmpHighlight = null;
        /// <summary>
        /// highlight image of this instance of the classButton depending on the Tree-Item associated with this button
        /// </summary>
        public Bitmap bmpHighlight
        {
            get
            {
                if (_bmpHighlight == null)
                {
                    _bmpHighlight = new Bitmap(bmp);
                    using (Graphics g = Graphics.FromImage(_bmpHighlight))
                    {
                        g.FillRectangle(cParentRegion.brForeground, recText);
                        g.DrawString(Text, cParentRegion.font, cParentRegion.brBackground, recText.Location);
                    }
                }
                return _bmpHighlight;
            }
            set { _bmpHighlight = value; }
        }

        /// <summary>
        /// Directory Tree-Item associated with this
        /// </summary>
        public classTreeItem cTI = null;

        /// <summary>
        /// rectangle which this button's text occupies on the button - used to quickly redraw highlight changes to the button
        /// </summary>
        public Rectangle recText = new Rectangle();

        /// <summary>
        /// font in which this button is drawn
        /// </summary>
        public Font fnt = new Font("ms sans-serif", 10);

        /// <summary>
        /// rectangle which this button's icon occupies on the button - used to quickly redraw highlight changes to the button
        /// </summary>
        public Rectangle recIcon = new Rectangle();

        bool bolCanBeToggled = false;
        /// <summary>
        /// determines whether or not this button can be toggled (used when the GUI-FileDialog associated with this button has its MultiFileSelection Property true)
        /// </summary>
        public bool CanBeToggled
        {
            get { return bolCanBeToggled; }
            set { bolCanBeToggled = value; }
        }

        bool bolToggled = false;
        /// <summary>
        /// determines whether this button is toggled (can only be toggled if its CanBeToggled property is true)
        /// </summary>
        public bool Toggled
        {
            get { return bolToggled; }
            set
            {
                if (bolToggled != value)
                {
                    bolToggled = value;
                    cParentRegion.Highlight = true;
                    Refreshed = false;
                    HighLight = bolToggled;
                }
            }
        }

        /// <summary>
        /// toggles this button's Toggle Property if this button's CanBeToggled property is true
        /// </summary>
        public void Toggle()
        {
            Toggled = !Toggled;
        }

        string strText = "";
        /// <summary>
        /// text displayed on this button
        /// </summary>
        public string Text
        {
            get { return strText; }
            set { strText = value; }
        }

        bool bolHighlight = false;
        /// <summary>
        /// determines whether or not this button is to be highlighted (either toggled or highlighted will return true)
        /// </summary>
        public bool HighLight
        {
            get { return bolHighlight || Toggled; }
            set
            {
                if (bolHighlight != value)
                {
                    bolHighlight = value;
                    Refreshed = false;
                    cParentRegion.Highlight = true; ;
                }
            }
        }

        bool bolRefreshed = false;
        /// <summary>
        /// determines whether this button needs to be redrawn
        /// </summary>
        public bool Refreshed
        {
            get { return bolRefreshed; }
            set { bolRefreshed = value; }
        }

    }

    /// <summary>
    /// class used to define a SearchPattern for the CurrentDirectoryContent file list
    /// </summary>
    public class classFileFilterItem
    {
        /// <summary>
        /// SearchPattern is used by the System.Directory.GetFiles( <directory>, <searchPattern>) function
        /// </summary>
        public string SearchPattern = "*.*";

        /// <summary>
        /// label displayed in the UserInput_Filter Region when this Filter Item is selected
        /// </summary>
        public string Label = "All Files (*.*)";

        /// <summary>
        /// instantiates an instance of this class
        /// </summary>
        /// <param name="strSearchPattern">SearchPattern specified for this instance</param>
        /// <param name="strLabel">label specified for this instance</param>
        public classFileFilterItem(string strSearchPattern, string strLabel)
        {
            SearchPattern = strSearchPattern;
            Label = strLabel;
        }

        /// <summary>
        /// takes the Filter specified by the Developer and parses it out into individual SearchPattern/Label instances
        /// </summary>
        /// <param name="strFilter">Filter specified by the Developer during RunTime</param>
        /// <returns>a list of classFileFilterItems made of the the parsed Filter provided</returns>
        public static List<classFileFilterItem> Parse(string strFilter)
        {
            char[] chrSplit = { '|' };
            string[] strTemp = strFilter.Split(chrSplit);
            List<classFileFilterItem> lstRetVal = new List<classFileFilterItem>();
            if (strTemp.Length % 2 == 0)
            {
                for (int intCounter = 0; intCounter < strTemp.Length / 2; intCounter++)
                {
                    string strLabel = strTemp[intCounter * 2];
                    string strSearchPattern = strTemp[intCounter * 2 + 1];
                    lstRetVal.Add(new classFileFilterItem(strSearchPattern, strLabel));
                }
            }
            return lstRetVal;
        }
    }

    /// <summary>
    /// class used to store and retrieve File icon sorted by File-Extensions
    /// </summary>
    public class classFileIcons
    {
        /// <summary>
        /// pointer to the root of the Binary-Tree containing the file-icons 
        /// </summary>
        static classBinTreeElement cRoot = null;

        /// <summary>
        /// searches the Binary-Tree for a File Extension's Icon and returns that icon if one is found
        /// </summary>
        /// <param name="strFileExtension">file extension used as a search parameter in the binary-tree</param>
        /// <returns>the icon requested if one is found or NULL if the requested icon is not found</returns>
        public static Icon Search(string strFileExtension)
        {
            strFileExtension = strFileExtension.ToUpper().Trim();
            classBinTreeElement cBinEle = cRoot;

            while (cBinEle != null)
            {
                int intComparisonResult = string.Compare(strFileExtension, cBinEle.Key);
                if (intComparisonResult < 0)
                    cBinEle = cBinEle.Left;
                else if (intComparisonResult > 0)
                    cBinEle = cBinEle.Right;
                else
                    return cBinEle.ico;
            }

            return null;
        }

        /// <summary>
        /// inserts a file-icon into the binary tree sorted by its File-Extension
        /// </summary>
        /// <param name="strFileExtension">File Extension used to sort this File-Icon into the binary-tree</param>
        /// <param name="icoNew">File-Icon to be stored</param>
        public static void Insert(string strFileExtension, ref Icon icoNew)
        {
            strFileExtension = strFileExtension.ToUpper().Trim();
            if (strFileExtension.Length < 1) return;
            if (cRoot == null)
            {
                cRoot = new classBinTreeElement(strFileExtension, ref icoNew);
                return;
            }

            classBinTreeElement cBinEle = cRoot;
            while (true)
            {
                int intComparisonRresult = string.Compare(strFileExtension, cBinEle.Key);
                if (intComparisonRresult < 0)
                {
                    if (cBinEle.Left != null)
                        cBinEle = cBinEle.Left;
                    else
                    {
                        cBinEle.Left = new classBinTreeElement(strFileExtension, ref icoNew);
                        return;
                    }
                }
                else if (intComparisonRresult > 0)
                {
                    if (cBinEle.Right != null)
                        cBinEle = cBinEle.Right;
                    else
                    {
                        cBinEle.Right = new classBinTreeElement(strFileExtension, ref icoNew);
                        return;
                    }
                }
                else
                {
                    return;
                }
            }
        }

        /// <summary>
        /// string used to hold the results of a tree Traversal that returns the list of File-Extensions currently in the Binary-Tree
        /// </summary>
        static string strTraversalResult = "";

        /// <summary>
        /// traverses the Binary-Tree In-Order and returns a string of the File-Extensions found in the Tree
        /// </summary>
        /// <returns></returns>
        public static string Traverse()
        {
            strTraversalResult = "";
            Traverse_Recurse(ref cRoot);
            return strTraversalResult;
        }

        /// <summary>
        /// traverses the Binary-Tree In-Order recursively and appends strFileExtension with input parameter BinTreeElement's FileExtension
        /// </summary>
        /// <param name="cBinEle">reference to input BinTree element</param>
        static void Traverse_Recurse(ref classBinTreeElement cBinEle)
        {
            if (cBinEle == null) return;
            Traverse_Recurse(ref cBinEle.Left);
            strTraversalResult += cBinEle.Key + ".";
            Traverse_Recurse(ref cBinEle.Right);
        }

        /// <summary>
        /// class of File-Icon Binary Tree elements
        /// </summary>
        public class classBinTreeElement
        {
            /// <summary>
            /// file-extension used for sorting in the tree
            /// </summary>
            public string Key = "";
            /// <summary>
            /// pointer to this Bin-Tree element's left child
            /// </summary>
            public classBinTreeElement Left = null;
            /// <summary>
            /// pointer to this Bin-Tree element's right child
            /// </summary>
            public classBinTreeElement Right = null;
            /// <summary>
            /// icon stored in this BinTree Element
            /// </summary>
            public Icon ico = null;

            /// <summary>
            /// instantiates an instance of this class without any parameters
            /// </summary>
            public classBinTreeElement()
            { }

            /// <summary>
            /// instantiates an instance of this class with a File-Extension & its associated Icon
            /// </summary>
            /// <param name="strKey">File Extension used to sort Icons in the tree</param>
            /// <param name="ico">icon this BinTree element holds in storage</param>
            public classBinTreeElement(string strKey, ref Icon ico)
            {
                Key = strKey.ToUpper().Trim();
                this.ico = ico;
            }
        }

    }

    #endregion

    #region SweepAndClean
    /// <summary>
    /// algorithm that maps a 2-D space and quickly retrieves rectangular elements from it
    /// </summary>
    public class classSweepAndPrune
    {
        /// <summary>
        /// list of all elements in this instance of the SweepAndPrune algorithm
        /// </summary>
        public List<classElement> lstElements = new List<classElement>();

        /// <summary>
        /// class used to describe the elements in the SweepAndPrune region
        /// </summary>
        public class classElement
        {
            /// <summary>
            /// rectangular area that defines' this element's sub-region within the Greater SweepAndPrune Region
            /// </summary>
            public Rectangle rec = new Rectangle();
            /// <summary>
            /// pointer to an object this element holds
            /// </summary>
            public object obj;

            /// <summary>
            /// tag object used by developer for various sordid and nefarious reasons modesty prevents us from revealing 
            /// </summary>
            public object tag;
        }

        /// <summary>
        /// adds an element SweepAndPrune algorithm
        /// </summary>
        /// <param name="cEle">element being added to the algorithm</param>
        public void Add(ref classElement cEle)
        {
            if (!lstElements.Contains(cEle))
            {
                lstElements.Add(cEle);
                Reset();
            }
        }

        /// <summary>
        /// removes an element from the algorithm
        /// </summary>
        /// <param name="cEle">element to be removed from the SweepAndPrune algorithm</param>
        public void Sub(ref classElement cEle)
        {
            if (lstElements.Contains(cEle))
            {
                lstElements.Remove(cEle);
                Reset();
            }
        }

        /// <summary>
        /// searches the list of rectangular subregions to discover which region contains the point specified
        /// </summary>
        /// <param name="pt">point searched for</param>
        /// <returns>returns an element whose region contains the specified point if such a region exists</returns>
        public classElement Search(Point pt)
        {
            classElement[] arrTemp = new classElement[lstElements.Count];
            lstElements.CopyTo(arrTemp);

            List<classElement> lstH = Search_H(pt);

            if (lstH != null && lstH.Count > 0)
            {
                List<classElement> lstV = Search_V(pt);
                if (lstV != null && lstV.Count > 0)
                {
                    List<classElement> lstShortest = null;
                    List<classElement> lstLongest = null;
                    if (lstV.Count != lstH.Count)
                    {
                        lstShortest = lstV.Count < lstH.Count
                                                 ? lstV
                                                 : lstH;
                        lstLongest = lstV.Count > lstH.Count
                                                ? lstV
                                                : lstH;
                    }
                    else
                    {
                        lstShortest = lstV;
                        lstLongest = lstH;
                    }
                    for (int intCounter = 0; intCounter < lstShortest.Count; intCounter++)
                    {
                        if (lstLongest.Contains(lstShortest[intCounter]))
                        {
                            lstElements = arrTemp.ToList<classElement>();
                            return lstShortest[intCounter];
                        }
                    }
                }
            }
            lstElements = arrTemp.ToList<classElement>();
            return null;
        }

        /// <summary>
        /// searches the list of Elements that are contained or touched by the borders of specified rectangle
        /// </summary>
        /// <param name="rec">rectangular area to be searched</param>
        /// <returns>list of elements which either touch or are contained inside the specified search area</returns>
        public List<classElement> Search(Rectangle rec) { return Search(rec.Location, new Point(rec.Right, rec.Bottom)); }

        /// <summary>
        /// seraches the list of elements that are contained or touched by the borders of the smalled rectangle that contains two specified points
        /// </summary>
        /// <param name="ptTL">Top-Left point of the rectangular area to be searched</param>
        /// <param name="ptBR">Bottom-Right point of the rectangular area to be searched</param>
        /// <returns>all elements that are either touched or contained within the specified search area</returns>
        public List<classElement> Search(Point ptTL, Point ptBR)
        {
            classElement[] arrTemp = new classElement[lstElements.Count];
            lstElements.CopyTo(arrTemp);

            List<classElementFind> lstH = Search_H(ptTL, ptBR);
            List<classElement> lstRetVal = new List<classElement>();
            if (lstH != null && lstH.Count > 0)
            {
                List<classElementFind> lstV = Search_V(ptTL, ptBR);
                if (lstV != null && lstV.Count > 0)
                {
                    for (int intHCounter = 0; intHCounter < lstH.Count; intHCounter++)
                    {
                        classElementFind cHEF = lstH[intHCounter];
                        for (int intHE = 0; intHE < cHEF.lstElements.Count; intHE++)
                        {
                            classElement cHE = cHEF.lstElements[intHE];
                            if (!lstRetVal.Contains(cHE))
                            {
                                bool bolFound = false;
                                for (int intVCounter = 0; !bolFound && intVCounter < lstV.Count; intVCounter++)
                                {
                                    classElementFind cVEF = lstV[intVCounter];
                                    for (int intVE = 0; !bolFound && intVE < cVEF.lstElements.Count; intVE++)
                                    {
                                        classElement cVE = cVEF.lstElements[intVE];
                                        if (cHE == cVE)
                                        {
                                            bolFound = true;
                                            lstRetVal.Add(cHE);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            lstElements = arrTemp.ToList<classElement>();
            return lstRetVal;
        }
        
        /// <summary>
        /// clears the scan-lists - lists must be reset when a change is made to any of the regions of elements the SweepAndPrune contains
        /// </summary>
        public void Reset()
        {
            lstHScan
                = lstVScan
                = null;
        }

        /// <summary>
        /// complete list of elements ordered by their horizontal values
        /// </summary>
        List<classElementFind> lstHScan = null;
        /// <summary>
        /// complete list of elements ordered by their vertical values
        /// </summary>
        List<classElementFind> lstVScan = null;

        /// <summary>
        /// searches the area for all elements that contain a specified X value
        /// </summary>
        /// <param name="pt">Point to be searched - only X is relevant</param>
        /// <returns></returns>
        List<classElement> Search_H(Point pt)
        {
            Build_Scan_H();
            if (lstHScan == null) Build_Scan_H();

            classElementFind cBFHFind = getBFElementContains(ref lstHScan, pt.X);
            if (cBFHFind != null) return cBFHFind.lstElements;
            return null;
        }

        /// <summary>
        /// searches for all elements that are contained between two points along the horizontal axis
        /// </summary>
        /// <param name="ptTL">Top-Left Point of region to be searched - only X is relevant</param>
        /// <param name="ptBR">Bottom-Right point of region to be searched - only X is relevant</param>
        /// <returns>returns a list of all elements that are within or touched by these two horizontal points</returns>
        List<classElementFind> Search_H(Point ptTL, Point ptBR)
        {
            Build_Scan_H();
            if (lstHScan == null) Build_Scan_H();

            List<classElementFind> lstBFHFind = getBFElementContains(ref lstHScan, ptTL.X, ptBR.X);
            if (lstBFHFind != null) return lstBFHFind;
            return null;
        }

        /// <summary>
        /// searches along the Vertical axis of a complete list of elements in SweepAndPrune algorithm
        /// </summary>
        /// <param name="pt">point searched</param>
        /// <returns>a list of elements that contain the specified point</returns>
        List<classElement> Search_V(Point pt)
        {
            //return lstElements;
            if (lstVScan == null) Build_Scan_V();

            classElementFind cBFVFind = getBFElementContains(ref lstVScan, pt.Y);
            if (cBFVFind != null) return cBFVFind.lstElements;
            return null;
        }

        /// <summary>
        /// Searches the SweepAndPrune region for all elements contained withint two Vertical points
        /// </summary>
        /// <param name="ptTL">Top-Left point of search area - only Y is relevant</param>
        /// <param name="ptBR">Bottom-Right point of search area - only Y is relevant</param>
        /// <returns>a list of all elements contained with the vertical points specified</returns>
        List<classElementFind> Search_V(Point ptTL, Point ptBR)
        {
            //return lstElements;
            if (lstVScan == null) Build_Scan_V();

            List<classElementFind> lstBFVFind = getBFElementContains(ref lstVScan, ptTL.Y, ptBR.Y);
            if (lstBFVFind != null) return lstBFVFind;
            return null;
        }

        /// <summary>
        /// scans the source list and creates a list subregions sorted by their X values that point to all source lists that cross that sub-region
        /// </summary>
        void Build_Scan_H()
        {
            // initialize list classElementFind elements
            {
                lstHScan = new List<classElementFind>();
                IEnumerable<classElement> query = lstElements.OrderBy(Element => Element.rec.Left);
                lstElements = (List<classElement>)query.ToList<classElement>();
                for (int intCounter = 0; intCounter < lstElements.Count; intCounter++)
                {
                    classElementFind cBFNew = new classElementFind();
                    classElement cEle = lstElements[intCounter];
                    if (cEle.rec.Width > 0)
                    {
                        cBFNew.intStart = cEle.rec.Left;
                        cBFNew.intEnd = cEle.rec.Right;
                        cBFNew.lstElements.Add(cEle);
                        lstHScan.Add(cBFNew);
                    }
                    else
                        ;
                }
            }
            BuildScan(ref lstHScan);
        }

        /// <summary>
        /// scans the source list and creates a list subregions sorted by their Y values that point to all source lists that cross that sub-region
        /// </summary>
        void Build_Scan_V()
        {
            // initialize list classElementFind elements
            {
                lstVScan = new List<classElementFind>();

                IEnumerable<classElement> query = lstElements.OrderBy(Element => Element.rec.Top);
                lstElements = (List<classElement>)query.ToList<classElement>();
                for (int intCounter = 0; intCounter < lstElements.Count; intCounter++)
                {
                    classElementFind cBFNew = new classElementFind();
                    classElement cEle = lstElements[intCounter];

                    if (cEle.rec.Height > 0)
                    {
                        cBFNew.intStart = cEle.rec.Top;
                        cBFNew.intEnd = cEle.rec.Bottom;
                        cBFNew.lstElements.Add(cEle);
                        lstVScan.Add(cBFNew);
                    }
                    else
                        ;
                }
            }
            BuildScan(ref lstVScan);
        }

        /// <summary>
        /// used by Build_Scan_V() & Build_Scan_H() both - to sort out sub regions in their respective Horizonta/Vertical axes
        /// </summary>
        /// <param name="lstScan"></param>
        void BuildScan(ref List<classElementFind> lstScan)
        {
            if (lstScan.Count > 0)
            // collate/expand list of classElementFind elements
            {
                classElementFind cBFMarker = null;
                int intIndex = 0;
                while (intIndex < lstScan.Count - 1)
                {
                    IEnumerable<classElementFind> queryHScan = lstScan.OrderBy(cBF => cBF.intStart);
                    lstScan = (List<classElementFind>)queryHScan.ToList<classElementFind>();
                    if (cBFMarker == null)
                    {
                        cBFMarker = lstScan[0];
                        intIndex = 0;
                    }
                    else
                        intIndex = lstScan.IndexOf(cBFMarker);

                    // gather elements in list that share the same start value
                    List<classElementFind> lstCommonStart = new List<classElementFind>();
                    do
                    {
                        if (lstScan[intIndex].intStart != lstScan[intIndex].intEnd)
                            lstCommonStart.Add(lstScan[intIndex]);
                        intIndex++;
                    } while (intIndex < lstScan.Count && lstScan[intIndex].intStart == cBFMarker.intStart);

                    // test if more than one element share the same start value
                    if (lstCommonStart.Count > 1)
                    {
                        IEnumerable<classElementFind> queryCommonStart = lstCommonStart.OrderBy(Element => Element.intEnd);
                        lstCommonStart = (List<classElementFind>)queryCommonStart.ToList<classElementFind>();

                        // reorder them in the source list according to their End values
                        int intStartIndex = lstScan.IndexOf(cBFMarker);
                        classElementFind[] arrStart = new classElementFind[intStartIndex];
                        classElementFind[] arrEnd = new classElementFind[lstScan.Count - intStartIndex - lstCommonStart.Count];
                        lstScan.CopyTo(0, arrStart, 0, intStartIndex);
                        lstScan.CopyTo(intStartIndex + lstCommonStart.Count, arrEnd, 0, lstScan.Count - intStartIndex - lstCommonStart.Count);

                        List<classElementFind> lstTest = new List<classElementFind>();
                        lstTest.AddRange(arrStart.ToList<classElementFind>());
                        lstTest.AddRange(lstCommonStart);
                        lstTest.AddRange(arrEnd.ToList<classElementFind>());

                        lstScan = new List<classElementFind>();
                        lstScan.AddRange(arrStart.ToList<classElementFind>());
                        lstScan.AddRange(lstCommonStart);
                        lstScan.AddRange(arrEnd.ToList<classElementFind>());

                        classElementFind cBFShortest = lstCommonStart[0];
                        lstCommonStart.Remove(cBFShortest);

                        // gather all Elements into the shortest element
                        for (int intCounter = 0; intCounter < lstCommonStart.Count; intCounter++)
                            cBFShortest.lstElements.AddRange(lstCommonStart[intCounter].lstElements);

                        // remove all elements that are the same length as the shortest
                        classElementFind cBFNext = lstCommonStart[0];
                        while (lstCommonStart.Count > 0
                                && cBFNext.intEnd == cBFShortest.intEnd)
                        {
                            lstCommonStart.Remove(cBFNext);
                            lstScan.Remove(cBFNext);
                            cBFNext = lstCommonStart.Count > 0 ? lstCommonStart[0] : null;
                        }

                        // adjust start value of all remaining elements in list 
                        for (int intCounter = 0; intCounter < lstCommonStart.Count; intCounter++)
                            lstCommonStart[intCounter].intStart = cBFShortest.intEnd;

                        cBFMarker = cBFShortest;
                        intIndex = lstScan.IndexOf(cBFMarker);
                    }
                    else if (lstCommonStart.Count > 0)
                    { // there is only one element with this start value
                        classElementFind cBFCurrent = lstCommonStart[0];
                        // test if next element in list starts before this one ends
                        intIndex = lstScan.IndexOf(cBFCurrent);
                        if (intIndex < lstScan.Count - 1)
                        {
                            classElementFind cBFNext = lstScan[intIndex + 1]; ;
                            if (cBFCurrent.intEnd > cBFNext.intStart)
                            { // this one overlaps with its neighbour - needs to be cut in two and inserted into the list
                                classElementFind cBFNew = new classElementFind();
                                cBFNew.intStart = cBFNext.intStart;
                                cBFNew.intEnd = cBFCurrent.intEnd;
                                cBFNew.lstElements.AddRange(cBFCurrent.lstElements);

                                cBFCurrent.intEnd = cBFNext.intStart;

                                lstScan.Add(cBFNew);
                            }
                            else
                                cBFMarker = lstScan[intIndex + 1];
                        }
                    }
                    else
                        break;
                }
            }
        }

        /// <summary>
        /// searches list provided for the sub-region that contains the value requested
        /// </summary>
        /// <param name="lst">list of sub-regions to be searched</param>
        /// <param name="intFind">value being searched</param>
        /// <returns>sub-region that contains the value being searched</returns>
        classElementFind getBFElementContains(ref List<classElementFind> lst, int intFind)
        {
            if (lst == null) return null;
            if (lst.Count == 0) return null;
            int intIndex = lst.Count / 2;
            int intStep = lst.Count / 2;
            List<classElementFind> lstTried = new List<classElementFind>();
            do
            {
                classElementFind cBF = lst[intIndex];
                if (lstTried.Contains(cBF)) return null;

                if (intFind >= cBF.intStart && intFind <= cBF.intEnd)
                    return cBF;
                lstTried.Add(cBF);
                intStep /= 2;
                if (intStep < 1)
                    intStep = 1;
                intIndex += intStep * (intFind < cBF.intStart ? -1 : 1);

            } while (intIndex >= 0 && intIndex < lst.Count);
            return null;
        }

        /// <summary>
        /// searches list provided for all sub-regions that are contained between the Find_min & Find_Max parameters
        /// </summary>
        /// <param name="lst">list of sub-regions to be searched</param>
        /// <param name="intFind_Min">minimum range of area being searched</param>
        /// <param name="intFind_Max">maximum range of area being searched</param>
        /// <returns>all subregions that are contained between the Find_Min & Find_max parameters</returns>
        List<classElementFind> getBFElementContains(ref List<classElementFind> lst, int intFind_Min, int intFind_Max)
        {
            if (lst == null) return null;
            if (lst.Count == 0) return null;
            int intIndex = lst.Count / 2;
            int intStep = lst.Count / 2;
            List<classElementFind> lstTried = new List<classElementFind>();
            int intIndex_Min = (lst.Count > 0 && lst[0].intStart > intFind_Min)
                                            ? 0
                                            : -1;
            int intIndex_Max = (lst.Count > 0 && lst[lst.Count - 1].intStart < intFind_Max)
                                        ? lst.Count - 1
                                        : -1;
            bool bolLoop_Min = true;
            do
            {
                classElementFind cBF = lst[intIndex];
                if (lstTried.Contains(cBF)) bolLoop_Min = false;// return null;

                //if (intFind_Min >= cBF.intStart && intFind_Min <= cBF.intEnd)
                if (intFind_Min <= cBF.intEnd
                    && (intIndex < intIndex_Min || intIndex_Min < 0))
                {
                    intIndex_Min = intIndex;
                    //bolLoop_Min = false;
                }
                lstTried.Add(cBF);
                intStep /= 2;
                if (intStep < 1)
                    intStep = 1;
                intIndex += intStep * (intFind_Min < cBF.intStart ? -1 : 1);

            } while (intIndex >= 0 && intIndex < lst.Count && bolLoop_Min);

            bool bolLoop_Max = true;
            intIndex = lst.Count / 2;
            lstTried.Clear();
            do
            {
                classElementFind cBF = lst[intIndex];
                if (lstTried.Contains(cBF)) bolLoop_Max = false;// return null;

                if (intFind_Max >= cBF.intStart && intIndex > intIndex_Max)// && intFind_Max <= cBF.intEnd)
                {
                    intIndex_Max = intIndex;
                    //bolLoop_Max = false;
                }
                lstTried.Add(cBF);
                intStep /= 2;
                if (intStep < 1)
                    intStep = 1;
                intIndex += intStep * (intFind_Max < cBF.intEnd ? -1 : 1);

            } while (intIndex >= 0 && intIndex < lst.Count && bolLoop_Max);

            if (intIndex_Min >= 0 && intIndex_Max >= 0 && intIndex_Min <= intIndex_Max)
            {
                List<classElementFind> lstRetVal = new List<classElementFind>();
                for (int intCounter = intIndex_Min; intCounter <= intIndex_Max; intCounter++)
                    lstRetVal.Add(lst[intCounter]);
                return lstRetVal;
            }

            return null;
        }

        /// <summary>
        /// class used to sub-divide SweepAndPrune area either horizontally or vertically
        /// </summary>
        public class classElementFind
        {
            /// <summary>
            /// list of elements that cross this sub-region
            /// </summary>
            public List<classElement> lstElements = new List<classElement>();

            int _intStart = 0;
            /// <summary>
            ///  this sub-region's minimum value 
            /// </summary>
            public int intStart
            {
                get { return _intStart; }
                set
                {
                    if (intStart != value)
                    {
                        _intStart = value;
                    }
                }
            }

            int _intEnd = 0;
            /// <summary>
            /// this sub-region's maximum value
            /// </summary>
            public int intEnd
            {
                get { return _intEnd; }
                set
                {
                    if (intEnd != value)
                    {
                        _intEnd = value;
                    }
                }
            }

            /// <summary>
            /// copies this instance and returns copy to calling function
            /// </summary>
            /// <returns>a copy of this instance</returns>
            public classElementFind Copy()
            {
                classElementFind cRetVal = new classElementFind();

                cRetVal.intStart = intStart;
                cRetVal.intEnd = intEnd;
                cRetVal.lstElements.AddRange(lstElements);

                return cRetVal;
            }
        }
    }
    #endregion

    #region PerPixelAlpha

    //
    // Copyright © 2002-2004 Rui Godinho Lopes <rui@ruilopes.com>
    // All rights reserved.
    //
    // This source file(s) may be redistributed unmodified by any means
    // PROVIDING they are not sold for profit without the authors expressed
    // written consent, and providing that this notice and the authors name
    // and all copyright notices remain intact.
    //
    // Any use of the software in source or binary forms, with or without
    // modification, must include, in the user documentation ("About" box and
    // printed documentation) and internal comments to the code, notices to
    // the end user as follows:
    //
    // "Portions Copyright © 2002-2004 Rui Godinho Lopes"
    //
    // An email letting me know that you are using it would be nice as well.
    // That's not much to ask considering the amount of work that went into
    // this.
    //
    // THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    // EXPRESS OR IMPLIED. USE IT AT YOUT OWN RISK. THE AUTHOR ACCEPTS NO
    // LIABILITY FOR ANY DATA DAMAGE/LOSS THAT THIS PRODUCT MAY CAUSE.
    //

    namespace PerPixelForm
    {
        // class that exposes needed win32 gdi functions.
        public class Win32
        {
            public enum Bool
            {
                False = 0,
                True
            };


            [StructLayout(LayoutKind.Sequential)]
            public struct Point
            {
                public Int32 x;
                public Int32 y;

                public Point(Int32 x, Int32 y) { this.x = x; this.y = y; }
            }


            [StructLayout(LayoutKind.Sequential)]
            public struct Size
            {
                public Int32 cx;
                public Int32 cy;

                public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; }
            }


            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            struct ARGB
            {
                public byte Blue;
                public byte Green;
                public byte Red;
                public byte Alpha;
            }


            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BLENDFUNCTION
            {
                public byte BlendOp;
                public byte BlendFlags;
                public byte SourceConstantAlpha;
                public byte AlphaFormat;
            }


            public const Int32 ULW_COLORKEY = 0x00000001;
            public const Int32 ULW_ALPHA = 0x00000002;
            public const Int32 ULW_OPAQUE = 0x00000004;

            public const byte AC_SRC_OVER = 0x00;
            public const byte AC_SRC_ALPHA = 0x01;


            [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

            [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern IntPtr GetDC(IntPtr hWnd);

            [DllImport("user32.dll", ExactSpelling = true)]
            public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool DeleteDC(IntPtr hdc);

            [DllImport("gdi32.dll", ExactSpelling = true)]
            public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool DeleteObject(IntPtr hObject);
        }



        /// <para>Your PerPixel form should inherit this class</para>
        /// <author><name>Rui Godinho Lopes</name><email>rui@ruilopes.com</email></author>
        public class _PerPixelAlphaForm : Form
        {
            public _PerPixelAlphaForm()
            {
                // This form should not have a border or else Windows will clip it.
                FormBorderStyle = FormBorderStyle.None;
            }


            /// <para>Changes the current bitmap.</para>
            public void SetBitmap(Bitmap bitmap)
            {
                SetBitmap(bitmap, 255);
            }

            /// <para>Changes the current bitmap with a custom opacity level.  Here is where all happens!</para>
            public void SetBitmap(Bitmap bitmap, byte opacity)
            {
                if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
                    throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");

                // The idea of this is very simple,
                // 1. Create a compatible DC with screen;
                // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
                // 3. Call the UpdateLayeredWindow.

                IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
                IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
                IntPtr hBitmap = IntPtr.Zero;
                IntPtr oldBitmap = IntPtr.Zero;
                try
                {
                    try
                    {
                        hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));  // grab a GDI handle from this GDI+ bitmap
                        oldBitmap = Win32.SelectObject(memDc, hBitmap);

                        Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
                        Win32.Point pointSource = new Win32.Point(0, 0);
                        Win32.Point topPos = new Win32.Point(Left, Top);
                        Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
                        blend.BlendOp = Win32.AC_SRC_OVER;
                        blend.BlendFlags = 0;
                        blend.SourceConstantAlpha = opacity;
                        blend.AlphaFormat = Win32.AC_SRC_ALPHA;

                        Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
                    }
                    finally
                    {
                        Win32.ReleaseDC(IntPtr.Zero, screenDc);
                        if (hBitmap != IntPtr.Zero)
                        {
                            Win32.SelectObject(memDc, oldBitmap);
                            Win32.DeleteObject(hBitmap);
                        }
                        Win32.DeleteDC(memDc);
                    }
                }
                catch (Exception)
                {
                    try
                    {
                        Win32.ReleaseDC(IntPtr.Zero, screenDc);
                        if (hBitmap != IntPtr.Zero)
                        {
                            Win32.SelectObject(memDc, oldBitmap);
                            Win32.DeleteObject(hBitmap);
                        }
                        Win32.DeleteDC(memDc);
                    }
                    catch (Exception)
                    {
                    }
                }
            }


            protected override CreateParams CreateParams
            {
                get
                {
                    CreateParams cp = base.CreateParams;
                    cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
                    return cp;
                }
            }
        }
    }
    #endregion

}
