Click here to Skip to main content
15,895,667 members
Articles / Programming Languages / C#

Mars Mission (5) : the Chemistry of Fuel

Rate me:
Please Sign up or sign in to vote.
4.70/5 (10 votes)
18 Jul 2011CPOL37 min read 29.4K   6.2K   17  
adding chemical elements the ships can use as fuel, and a new auto-pilot feature
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows.Forms;
using System.Drawing;

namespace GraphicText
{
    #region "structures"
    public struct classWordImageLine
    {
		public classWordImage[] Word;
        public int intWidth;
        public int intHeight;
        public int intBottomEdgePos;
        public bool bolHasSubscript;
        public bool bolHasSuperscript;
    }
    public struct udtChemSymbols
    {
        public string[] Symbols;
    }
    #endregion

    #region "enumerated types"
    public enum enuWordPositionRelativeToPreviousWord { right, NL }
    #endregion

    public class classGraphicText
    {
        #region "variables"
        classMyFont Font_Normal;
        static classWordImage WordImage_BinTree;
        static udtChemSymbols[] udrChemSymbols;
        static public int intHTab = 40;
        static public int intVTab = 25;
		static public string strAlpha = "aàáâãäåbcçdÐeèéêëfghiìíîïjklmnñoðòóôõöpqrsštuùúûüvwxyýÿzžAÀÁÂÃÄÅBCÇDÐEÈÉÊËFGHIÌÍÎÏJKLMNÑOÐÒÓÔÕÖPQRSŠTUÙÚÛÜVWXYÝŸZŽĀĒĪŌŪāēīōū";
        static public Color clrBackground = Color.White;
        static classWordImageLine[] udrLines = new classWordImageLine[0];                    
        #endregion

        #region "object"
		static Bitmap bmpSizer = new Bitmap(10, 10);
		static Graphics g = Graphics.FromImage(bmpSizer);
		#endregion

        public classGraphicText()
        {   
            udrChemSymbols = new udtChemSymbols[2];
            string[] strTemp0 = { "B", "C", "D", "F", "H", "I", "K", "N", "O", "P", "S", "U", "V", "W", "Y" };
            udrChemSymbols[0].Symbols = strTemp0;
            string[] strTemp1 = { "Ac", "Ag", "Al", "Am", "Ar", "As", "At", "Au", "Ba", "Be", "Bh", "Bi", "Bk", "Br", "Ca", "Cd", "Ce", "Cf", "Cl", "Cm", "Co", "Cp", "Cr", "Cs", "Cu", "Db", "Ds", "Dy", "Er", "Es", "Eu", "Fe", "Fm", "Fr", "Ga", "Gd", "Ge", "He", "Hf", "Hg", "Ho", "Hs", "In", "Ir", "Kr", "La", "Li", "Lr", "Lu", "Md", "Mg", "Mn", "Mo", "Mt", "Na", "Nb", "Nd", "Ne", "Ni", "No", "Np", "Os", "Pa", "Pb", "Pd", "Pm", "Po", "Pr", "Pt", "Pu", "Ra", "Rb", "Re", "Rf", "Rg", "Rh", "Rn", "Ru", "Sb", "Sc", "Se", "Sg", "Si", "Sm", "Sn", "Sr", "Ta", "Tb", "Tc", "Te", "Th", "Ti", "Tl", "Tm", "Xe", "Yb", "Zn", "Zr" };
            udrChemSymbols[1].Symbols = strTemp1;

            Font_Normal = new classMyFont(new Font("Ms sans-serif", 10, FontStyle.Regular), Color.Black);
        }

        public classWordImage getWordUnderMouse(Point ptMouse, classWordImage[] cWordArray)
        {
            int intLineIndex = 0;
            while (intLineIndex < udrLines.Length && udrLines[intLineIndex].intBottomEdgePos < ptMouse.Y)
                intLineIndex++;

            if (intLineIndex >= 0
                && intLineIndex < udrLines.Length
                && udrLines.Length > 0)
            {
                for (int intWordCounter = 0; intWordCounter < udrLines[intLineIndex].Word.Length; intWordCounter++)
                {
                    classWordImage cWord = udrLines[intLineIndex].Word[intWordCounter];
                    if (cWord.strText != null
                        && cWord.pt.Y <= ptMouse.Y
                        && cWord.pt.Y + cWord.bmp.Height >= ptMouse.Y
                        && cWord.pt.X <= ptMouse.X
                        && cWord.pt.X + cWord.bmp.Width >= ptMouse.X)
                        return udrLines[intLineIndex].Word[intWordCounter];
                }
            }
            return null;
        }

        /// <summary>
        /// returns the classWordImage located beneath the current mousepointer on the picbox's image 
        /// </summary>
        /// <returns>classWordImage beneath the mouse or null if none found</returns>
        /// 
        public classWordImage getWordUnderMouse_old(Point ptMouse, classWordImage[] cWordArray)
        {
            
            int intStepSize = cWordArray.Length;
            int intIndex = 0;
            while (intStepSize > 1 && intIndex < cWordArray.Length && intIndex >= 0)
            {
                intStepSize = (int)Math.Ceiling((double)intStepSize / 2);
                
                if (ptMouse.Y > cWordArray[intIndex].intLine)
                {
                    if (intIndex + intStepSize >= cWordArray.Length)
                        intIndex = cWordArray.Length - 1;
                    else
                        intIndex += intStepSize;
                }
                else if (ptMouse.Y < cWordArray[intIndex].intLine - wordSize(cWordArray[intIndex]).Height)
                {
                    if (intIndex - intStepSize < 0)
                        intIndex = 0;
                    else
                        intIndex -= intStepSize;
                }
                else
                    break;
            }

            int intDir = -1;
            if (intIndex >= 0 && intIndex < cWordArray.Length)
            {

                if (ptMouse.X > cWordArray[intIndex].pt.X)
                    intDir = 1;
                int intThisDir = 0;

                while (intIndex >= 0
                        && intIndex < cWordArray.Length)
                {
                    Size szWord = wordSize(cWordArray[intIndex]);
                    if (ptMouse.X > cWordArray[intIndex].pt.X + szWord.Width
                        || cWordArray[intIndex].eWordImageType == enuWordImageType.vTab )
                        intThisDir = 1;
                    else if (ptMouse.X < cWordArray[intIndex].pt.X)
                        intThisDir = -1;
                    else
                    {
                        if (ptMouse.X > cWordArray[intIndex].pt.X
                            && ptMouse.X < cWordArray[intIndex].pt.X + szWord.Width
                            && ptMouse.Y > cWordArray[intIndex].pt.Y
                            && ptMouse.Y < cWordArray[intIndex].pt.Y + szWord.Height)
                        {
                            return cWordArray[intIndex];
                        }
                    }
                    if (intDir != intThisDir)
                        return null;
                    else
                        intIndex += intThisDir;
                }
            }

            return null;
        }


        public Color  TextBackGroundColor 
        {
            set
            {
                clrBackground = value;
            }
            get
            {
                return clrBackground;
            }
        }

        static public Size wordSize(classWordImage cWord)
        {
            switch (cWord.eWordImageType)
            {
                case enuWordImageType.vTab:
                case enuWordImageType.hTab:
                    return new Size(intHTab, intVTab);

                default:
                    return cWord.bmp.Size;
            }
        }
        
        /// <chform>  
        /// plain,      Chemical formula.  The letters are plain font,
        /// numbers     but the numbers are subscript.   This is mostly
        /// subscript   useful as a functional mark to pinpoint
        ///             chemicals.
        public enum enuChemElementType { init, symbol, number }
        /// <summary>
        /// converts a string into classWordImage element with a single bitmap graphically depicting the formula and then appends the referenced classWordImage[] array
        /// </summary>
        /// <param name="udrWordImageArray">array to which the resultant image is appended</param>
        /// <param name="strChemFormula">input string describing a chemical formula</param>
        /// <param name="fntDefault">font used to display Chemical symbols</param>
		static public void appendWordImage_ChemicalFormula(ref classWordImage[] udrWordImageArray, string strChemFormula, classMyFont fntDefault)
		{
			appendWordImage_ChemicalFormula(ref udrWordImageArray, strChemFormula, fntDefault, false);
		}
        static public void appendWordImage_ChemicalFormula(ref classWordImage[] udrWordImageArray, string strChemFormula, classMyFont fntDefault, bool bolRecurse)
        {
            /// create an empty classWordImage[] array to hold all the image which comprise the output image
            classWordImage[] udrChemSymbols = new classWordImage[0];
            int intCurrentChar = 0;
            enuScript script = enuScript.normal;
            /// - scan the string and cut off characters grouping them into symbols or numbers
            /// - for each symbol collection e.g. 'Na' 'H' or unbroken number collection '2', '12'
            ///    create a classWordImage element appending it to the udrChemSymbols[] array
            ///    and setting the 'script' to 'normal' for symbols and 'sub'(subscript) for numbers
            /// - when the entire formula has been scanned assemble them into one image
            /// - create a new classWordImage element
            ///   - set its bitmap to the new image created by combining all symbol/number images
            ///   - append new classWordImage element to input parameter reference array & quit
            while (intCurrentChar < strChemFormula.Length)
            {
                string strThisElement = "";
                classMyFont fntNew = null;
                if (intCurrentChar < strChemFormula.Length - 1
                    && isAlpha(strChemFormula[intCurrentChar])
                    && isAlpha(strChemFormula[intCurrentChar + 1])
                    && isLowerCaseAlpha(strChemFormula[intCurrentChar + 1])
                    && isChemSymbol(strChemFormula.Substring(intCurrentChar, 2)))
                {
                    strThisElement = strChemFormula.Substring(intCurrentChar, 2);
                    script = enuScript.normal;
                    intCurrentChar += 2;
                    fntNew = fntDefault;
                }
                else if (isAlpha(strChemFormula[intCurrentChar])
                       && isChemSymbol(strChemFormula.Substring(intCurrentChar, 1)))
                {
                    strThisElement = strChemFormula.Substring(intCurrentChar, 1);
                    script = enuScript.normal;
                    intCurrentChar += 1;
                    fntNew = fntDefault;
                }
                else if (isANumber(strChemFormula[intCurrentChar]))
                {
                    strThisElement = "";
                    while (intCurrentChar < strChemFormula.Length && isANumber(strChemFormula[intCurrentChar]))
                    {
                        strThisElement += strChemFormula.Substring(intCurrentChar, 1);
                        script = enuScript.sub;
                        intCurrentChar += 1;
                    }
                    int intNewSize = (int)((double)fntDefault.fnt.Size / 2.0);
                    if (intNewSize < 8)
                        intNewSize = 8;
                    fntNew = new classMyFont(new Font(fntDefault.fnt.FontFamily, intNewSize, fntDefault.fnt.Style), fntDefault.foreColor);
                }
				else if (strChemFormula[intCurrentChar] == '(')
				{
					int intNumOpen = 1, intNumClose = 0;
					int intOpenChar = intCurrentChar;
					while (intNumOpen != intNumClose && intCurrentChar < strChemFormula.Length) 
					{
						intCurrentChar++;
						if (strChemFormula[intCurrentChar] == '(') intNumOpen++;
						if (strChemFormula[intCurrentChar] == ')') intNumClose++;
					}
					int intCloseChar = intCurrentChar;
					if (intCloseChar > intOpenChar + 2)
					{
						appendArrayWordImage(ref udrChemSymbols, "(", fntDefault, enuWordPositionRelativeToPreviousWord.right, enuScript.normal, enuWordImageType.plain);

						string strSubFormula = strChemFormula.Substring(intOpenChar + 1, intCloseChar - intOpenChar - 1);
						classWordImage[] udrSubChemSymbols = new classWordImage[0];
						appendWordImage_ChemicalFormula(ref udrSubChemSymbols, strSubFormula, fntDefault, true);
						setWordImage(ref udrSubChemSymbols[0]);
						udrSubChemSymbols[0].myPosRelToPrev = enuWordPositionRelativeToPreviousWord.right;
						List<classWordImage> lWordImage = udrChemSymbols.ToList();
						List<classWordImage> lSubWordImage = udrSubChemSymbols.ToList();
						lWordImage.AddRange(lSubWordImage);
						udrChemSymbols = lWordImage.ToArray();
						//udrChemSymbols[udrChemSymbols.Length - 2].bmp.Save("c:\\temp\\formula.bmp");
						appendArrayWordImage(ref udrChemSymbols, ")", fntDefault, enuWordPositionRelativeToPreviousWord.right, enuScript.normal, enuWordImageType.plain);
					}
					intCurrentChar++;
				}
				else
				{
					strThisElement = "";
				}
                if (strThisElement.Length > 0) appendArrayWordImage(ref udrChemSymbols, strThisElement, fntNew, enuWordPositionRelativeToPreviousWord.right, script, enuWordImageType.plain);
            }

			for (int intChemSymbolCounter = 0; intChemSymbolCounter < udrChemSymbols.Length; intChemSymbolCounter++)
			{
				setWordImage(ref udrChemSymbols[intChemSymbolCounter]);
			}
            udrChemSymbols[0].myPosRelToPrev = enuWordPositionRelativeToPreviousWord.NL;

            Array.Resize<classWordImage>(ref udrWordImageArray, udrWordImageArray.Length + 1);
            udrWordImageArray[udrWordImageArray.Length - 1] = new classWordImage();
            udrWordImageArray[udrWordImageArray.Length - 1].strText = strChemFormula;
            udrWordImageArray[udrWordImageArray.Length - 1].myPosRelToPrev = enuWordPositionRelativeToPreviousWord.right;
            udrWordImageArray[udrWordImageArray.Length - 1].fnt = fntDefault;
            udrWordImageArray[udrWordImageArray.Length - 1].script = enuScript.normal;
			SizeF szf = g.MeasureString(strChemFormula, fntDefault.fnt);
			Bitmap bmpSource = putImageArrayOntoBitmap((int)(szf.Width*1.5), udrChemSymbols);
			int intClipTop = 7  
							+ (bolRecurse 
									? 2
									: 0);
			int intHeight = 27;

			int intWidth = bmpSource.Width - 5;
			Bitmap bmpFormula = new Bitmap(intWidth, intHeight);
			using (Graphics gFormula = Graphics.FromImage(bmpFormula))
			{
				Rectangle recSrc = new Rectangle(0, intClipTop, bmpFormula.Width, bmpFormula.Height);
				Rectangle recDest = new Rectangle(0, 0, bmpFormula.Width, bmpFormula.Height);
				gFormula.DrawImage(bmpSource, recDest, recSrc, GraphicsUnit.Pixel);
			}

			udrWordImageArray[udrWordImageArray.Length - 1].bmp = bmpFormula;

			//udrWordImageArray[udrWordImageArray.Length - 1].bmp.Save("c:\\temp\\formula.bmp");
            udrWordImageArray[udrWordImageArray.Length - 1].bmp.MakeTransparent(udrWordImageArray[udrWordImageArray.Length - 1].bmp.GetPixel(0, 0));
            szf = g.MeasureString("H", fntDefault.fnt);
            udrWordImageArray[udrWordImageArray.Length - 1].intBaseline = (int)szf.Height;
        }

		static public Bitmap getImageChemicalFormula(string strFormula, Font fnt, Color clr) { return getImageChemicalFormula(strFormula, new classMyFont(fnt, clr)); }
		static public Bitmap getImageChemicalFormula(string strFormula, classMyFont cFnt)
		{
			classWordImage[] udrWordImage = new classWordImage[0];
			appendWordImage_ChemicalFormula(ref udrWordImage, strFormula, cFnt);
			
			return udrWordImage[0].bmp;
		}
		
        static public bool isChemSymbol(string strCS)
        {
            /// udrChemSymbols as two arrays of strings
            /// [0] has all one character chemical symbols
            /// [1] has all two character chemical symbols
            ///  -> use the array which corresponds to the size of the input string 'strCS'
            string[] strSymbols = udrChemSymbols[strCS.Length - 1].Symbols;

            /// chemical symbols are ordered alphabetically
            /// jump up/down the list halfing the distance last jumped(intStepSize = intStepSize/2) as long as intStepSize >1
			int intStepSize = strSymbols.Length;
            int intIndex = 0;
            int intCompareResult = 0;
            while (intStepSize > 1)
            {
                intStepSize = (int)Math.Floor((double)intStepSize / 2);
                intCompareResult = strCS.CompareTo(strSymbols[intIndex]);
                if (intCompareResult > 0)
                    intIndex += intStepSize;
                else if (intCompareResult < 0)
                    intIndex -= intStepSize;
                else
                    return true;
            }

            // step by one in appropriate direction until find or quit
            if (intCompareResult > 0)
            {
                while (intCompareResult > 0 && intIndex >= 0)
                {
                    intCompareResult = strCS.CompareTo(strSymbols[intIndex]);
                    if (intCompareResult > 0)
                        intIndex += intStepSize;
                    else if (intCompareResult < 0)
                        intIndex -= intStepSize;
                    else
                        return true;
                }
            }
            else
            {
                while (intCompareResult < 0 && intIndex < strSymbols.Length)
                {
                    intCompareResult = strCS.CompareTo(strSymbols[intIndex]);
                    if (intCompareResult > 0)
                        intIndex += intStepSize;
                    else if (intCompareResult < 0)
                        intIndex -= intStepSize;
                    else
                        return true;
                }
            }
            return false;

        }
        static public bool isANumber(char c) { return (c >= '0' && c <= '9'); }
		static public bool isAlpha(char c) { return (strAlpha.Contains(c)); }
		static public bool isLowerCaseAlpha(char c) { return (strAlpha.Substring(0, strAlpha.Length / 2).Contains(c)); }

        /// <summary>
        /// creates new WordImage element, inserts it into empty array and returns result
        /// </summary>
        /// <param name="strText">text for new element</param>
        /// <param name="fnt">font for new element</param>
        /// <param name="script">script of new element</param>
        /// <returns>classWordImage element</returns>
		static public classWordImage[] getWordImageArray(string strText, classMyFont fnt, enuScript script)
        {
            classWordImage[] udrRetVal = new classWordImage[0];
            return getWordImageArray(ref udrRetVal, strText, fnt, script);
        }

        /// <summary>
        /// creates a new classWordImage element and appends it to referenced array then returns referenced array
        /// </summary>
        /// <param name="udrWordImageArray">array to which new element will be appended</param>
        /// <param name="strText">text of new element</param>
        /// <param name="fnt">font of new element</param>
        /// <param name="script">script of new element</param>
        /// <returns>input reference array with new element appended to it</returns>
		static public classWordImage[] getWordImageArray(ref classWordImage[] udrWordImageArray, string strText, classMyFont fnt, enuScript script)
        {
            appendArrayWordImage(ref udrWordImageArray, strText, fnt, enuWordPositionRelativeToPreviousWord.NL, script, enuWordImageType.plain);
            return udrWordImageArray;
        }

        /// <summary>
        /// creates a new classWordImage element and appends it to referenced array then returns referenced array
        /// </summary>
        /// <param name="udrWordImageArray">array to which new element will be appended</param>
        /// <param name="strText">text of new element</param>
        /// <param name="fnt">font of new element</param>
        /// <param name="PosFirstWordRelToPrev">position of new element relative to the previous</param>
        /// <param name="script">script of new element</param>
		static public void appendArrayWordImage(ref classWordImage[] udrWordImages, string strText, classMyFont fnt, enuWordPositionRelativeToPreviousWord PosFirstWordRelToPrev, enuScript script, enuWordImageType wordTypeForEntireString)
        { appendArrayWordImage(ref udrWordImages, strText, fnt, PosFirstWordRelToPrev, script, wordTypeForEntireString, ""); }
        /// <summary>
        /// creates a new classWordImage element and appends it to referenced array then returns referenced array
        /// </summary>
        /// <param name="udrWordImageArray">array to which new element will be appended</param>
        /// <param name="strText">text of new element</param>
        /// <param name="fnt">font of new element</param>
        /// <param name="PosFirstWordRelToPrev">position of new element relative to the previous</param>
        /// <param name="script">script of new element</param>
        /// <param name="strAddress">only necessary if the wordTypeForEntireString is 'link'</param>
		static public void appendArrayWordImage(ref classWordImage[] udrWordImages, string strText, classMyFont fnt, enuWordPositionRelativeToPreviousWord PosFirstWordRelToPrev, enuScript script, enuWordImageType wordTypeForEntireString, string strAddress)
        {
            string[] strParagraphs = strText.Split("\r\n".ToCharArray());
            if (strText.Length == 0)
                return;
            foreach (string strParagraph in strParagraphs)
            {
                string[] strWords = divideStringIntoWords(strParagraph);

                for (int intWordCounter = 0; intWordCounter < strWords.Length; intWordCounter++)
                {
                    if (strWords != null 
                        && intWordCounter < strWords.Length
                        && strWords[intWordCounter] != null
                        && strWords[intWordCounter][0] == '\t')
                    {
                        Array.Resize<classWordImage>(ref udrWordImages, udrWordImages.Length + 1);
                        udrWordImages[udrWordImages.Length - 1] = new classWordImage();
                        udrWordImages[udrWordImages.Length - 1].myPosRelToPrev = enuWordPositionRelativeToPreviousWord.right;
                        udrWordImages[udrWordImages.Length - 1].eWordImageType = enuWordImageType.hTab;
                        setWordImage(ref udrWordImages[udrWordImages.Length - 1]);
                    }
                    else if (strWords[intWordCounter] != null)
                    {
                        Array.Resize<classWordImage>(ref udrWordImages, udrWordImages.Length + 1);
                        udrWordImages[udrWordImages.Length - 1] = new classWordImage();
                        udrWordImages[udrWordImages.Length - 1].strText = strWords[intWordCounter];
                        udrWordImages[udrWordImages.Length - 1].myPosRelToPrev = (intWordCounter == 0) ? PosFirstWordRelToPrev : enuWordPositionRelativeToPreviousWord.right;
                        udrWordImages[udrWordImages.Length - 1].fnt = fnt;
                        udrWordImages[udrWordImages.Length - 1].script = script;
                        udrWordImages[udrWordImages.Length - 1].eWordImageType = wordTypeForEntireString;
                        if (wordTypeForEntireString == enuWordImageType.link
                            || wordTypeForEntireString == enuWordImageType.solution
                            || wordTypeForEntireString == enuWordImageType.flash)
                            udrWordImages[udrWordImages.Length - 1].strAddress = strAddress;
                        setWordImage(ref udrWordImages[udrWordImages.Length - 1]);
                    }
                }
            }
        }

		static public void appendArrayWordImage_withImage(ref classWordImage[] udrWordImages, Bitmap bmpSourceImage, string strText)
        {
            Array.Resize<classWordImage>(ref udrWordImages, udrWordImages.Length + 1);
            udrWordImages[udrWordImages.Length - 1] = new classWordImage();
            udrWordImages[udrWordImages.Length - 1].strText = strText;
            udrWordImages[udrWordImages.Length - 1].myPosRelToPrev = enuWordPositionRelativeToPreviousWord.NL;
            udrWordImages[udrWordImages.Length - 1].bmp = bmpSourceImage;
            udrWordImages[udrWordImages.Length - 1].eWordImageType = enuWordImageType.image;
            setWordImage(ref udrWordImages[udrWordImages.Length - 1]);
        }

        #region "get image for word"
		static public Bitmap getWordImage(string strWord, Font fnt, Color clr) { return getWordImage(strWord, new classMyFont(fnt, clr)); }
		static public Bitmap getWordImage(string strWord, classMyFont cgrFont)
		{
			classWordImage cWordImage = new classWordImage();
			cWordImage.strText = strWord;
			cWordImage.fnt = cgrFont;
			setWordImage(ref cWordImage);
			return cWordImage.bmp;
		}
		static public void setWordImage(ref classWordImage udrWordImage)
        {
            if (udrWordImage.bmp != null)
                return;
			if (udrWordImage.strText == null || udrWordImage.strText.Length == 0) return;
            // rectangle for quote
            if(false && (udrWordImage.strText == null || udrWordImage.strText.Length == 0))
            {
                udrWordImage.bmp = new Bitmap(1, 1);
                return;
            }

            if (false && WordSetInBinTree(ref udrWordImage))
                return;

            SizeF szf = g.MeasureString(udrWordImage.strText, udrWordImage.fnt.fnt);
			Rectangle quoteRect = new Rectangle(0,
			                                    0,
			                                    (int)szf.Width
			                                        + (int)(udrWordImage.fnt.fnt.Height * .5)
			                                        + (udrWordImage.fnt.fnt.Italic ? (int)(udrWordImage.fnt.fnt.Height * .3) : 0)
			                                        + (udrWordImage.fnt.fnt.Bold ? (int)(udrWordImage.fnt.fnt.Height * .2) : 0),
			                                    (int)(szf.Height * 1.3));
			
            // create a new bitmap that contains both the quote and the author text
            Bitmap bmpTemp = new Bitmap(quoteRect.Width, quoteRect.Height);
            using (Graphics gText = Graphics.FromImage(bmpTemp))
            {
                // set the text rendering characteristics
				gText.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
				gText.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

                // draw the text
				TextRenderer.DrawText(gText,
                                      udrWordImage.strText,
                                      udrWordImage.fnt.fnt,
                                      new Point(quoteRect.X + 5,
                                                quoteRect.Y),
                                      udrWordImage.fnt.foreColor,
                                      Color.White,
                                      TextFormatFlags.Default | TextFormatFlags.NoPrefix);
            }
            bmpTemp.MakeTransparent(Color.White);
            int intLeftCut = 7;
            int intWidth = bmpTemp.Width - intLeftCut;
            if (intWidth <= 0)
                intWidth = 1;
            udrWordImage.bmp = new Bitmap(intWidth, bmpTemp.Height);
            using (Graphics gText = Graphics.FromImage(udrWordImage.bmp))
            {
                Rectangle rectDest = new Rectangle(0, 0, wordSize(udrWordImage).Width , udrWordImage.bmp.Height);
                Rectangle rectSrc = new Rectangle(intLeftCut, 0, wordSize(udrWordImage).Width, udrWordImage.bmp.Height);
				gText.DrawImage(bmpTemp, rectDest, rectSrc, GraphicsUnit.Pixel);
            }
            udrWordImage.intBaseline = udrWordImage.bmp.Height;
        }

        /// <summary>
        /// tests if the word's image at required font, and forecolor exists in the wordimage_BinTree
        /// creates a pointer to input referenced wordImage element including it into the tree if there is none
        ///  - word images found in the tree are used instead of rebuilding them
        ///  - when images are not found here the calling function creates new images which the binary-tree already points to and can later return for reuse
        /// </summary>
        /// <param name="wordImage">referenced classWordImage element before a bitmap has been created</param>
        /// <returns>true if an image already exists, false if a new image needs to be created</returns>
        static public bool WordSetInBinTree(ref classWordImage wordImage)
        {
            //return false;
            classWordImage wiThis = WordImage_BinTree;
            if (wiThis == null)
            {
                WordImage_BinTree = wordImage;
                return false;
            }
            else
            {
                while (true)
                {
                    if (wordImage.strText.CompareTo(wiThis.strText) > 0)
                    {
                        if (wiThis.Search.right != null)
                            wiThis = wiThis.Search.right;
                        else
                        {
                            wiThis.Search.right = wordImage;
                            return false;
                        }
                    }
                    else if (wordImage.strText.CompareTo(wiThis.strText) < 0)
                    {
                        if (wiThis.Search.left != null)
                            wiThis = wiThis.Search.left;
                        else
                        {
                            wiThis.Search.left = wordImage;
                            return false;
                        }
                    }
                    else
                    {
                        while (true)
                        {
                            if (FontsAreTheSame(wiThis, wordImage))
                            {
                                wordImage.bmp = wiThis.bmp;
                                wordImage.intBaseline = wiThis.intBaseline;
                                return true;
                            }
                            else
                            {
                                if (wiThis.Search.next != null)
                                    wiThis = wiThis.Search.next;
                                else
                                {
                                    wiThis.Search.next = wordImage;
                                    wordImage.intBaseline = wiThis.intBaseline;
                                    return false;
                                }
                            }
                        }
                    }
                }
            }
        }

        static public bool FontsAreTheSame(classWordImage WI_A, classWordImage WI_B)
        {
            return (WI_A.fnt.fnt.Style == WI_B.fnt.fnt.Style
                   && WI_A.fnt.fnt.Size == WI_B.fnt.fnt.Size
                   && WI_A.fnt.fnt.FontFamily == WI_B.fnt.fnt.FontFamily
                   && WI_A.fnt.foreColor == WI_B.fnt.foreColor
                   && WI_A.eWordImageType == WI_B.eWordImageType);
        }

        #endregion
        /// <summary>
        /// takes input string and returns an array of strings keeping punctuation marks and non-alphabetical characters at the end of series of alphabetical characters
        /// </summary>
        /// <param name="strText">input text to be parsed into 'words'</param>
        /// <returns>array of 'words' with punctuation after alpha-characters, all words start with alpha and may or may not have punctuations at end including spaces</returns>
		static public string[] divideStringIntoWords(string strText)
        {
            string[] strRetVal = new string[1];
			string strText_LowerCase = strText.ToLower()
											.Replace("'", "A")
											.Replace(".", "A")
											.Replace("\"", "A")
											.Replace("\\", "A")
											.Replace("/", "A")
											.Replace("?", "A")
											.Replace("!", "A")
											.Replace("$", "A")
											.Replace("%", "A")
											.Replace("(", "A")
											.Replace(")", "A")
											.Replace("[", "A")
											.Replace("]", "A")
											.Replace("{", "A")
											.Replace("}", "A")
											.Replace(",", "A")
											.Replace("-", "A"); // the chars replaced will be force-drawn at end of word

            bool bolFoundPunctuation = false;
            bool bolThisCharPunctuation = false;
            for (int intCharCounter = 0; intCharCounter < strText.Length; intCharCounter++)
            {
                if (strText_LowerCase[intCharCounter] == '\t')
                {
                    strRetVal[strRetVal.Length - 1] = '\t'.ToString();
                    Array.Resize<string>(ref strRetVal, strRetVal.Length + 1);
                    bolFoundPunctuation = false;
                    
                }
                else
                {
                    bolThisCharPunctuation = !strAlpha.Contains(strText_LowerCase[intCharCounter]);
                    bolFoundPunctuation = bolFoundPunctuation || bolThisCharPunctuation;
                    if (bolFoundPunctuation && !bolThisCharPunctuation)
                    {
                        // new word
                        Array.Resize<string>(ref strRetVal, strRetVal.Length + 1);
                        bolFoundPunctuation = false;
                    }
                    strRetVal[strRetVal.Length - 1] += strText[intCharCounter];
                }
            }

            return strRetVal;
        }

        /// <summary>
        /// given the width of output image and an array of classWordImage[]s, this function juxtaposes all the input images into the shortest bitmap with prescribed input width
        /// </summary>
        /// <param name="intWidth">width of output image</param>
        /// <param name="cWordArray">array of classWordImage elements to be drawn onto a single bitmap</param>
        /// <returns>a bitmap comprised of images in input classWordImage[] array</returns>
        static public Bitmap putImageArrayOntoBitmap(int intWidth, classWordImage[] cWordArray)
        {
            udrLines = new classWordImageLine[0];
            return putImageArrayOntoBitmap(intWidth, cWordArray, ref udrLines); 
        }
		static public Bitmap putImageArrayOntoBitmap(int intWidth, classWordImage[] cWordArray, ref classWordImageLine[] udrLines) { return putImageArrayOntoBitmap(intWidth, cWordArray, ref udrLines, false); }
		static public Bitmap putImageArrayOntoBitmap(int intWidth, classWordImage[] cWordArray, ref classWordImageLine[] udrLines, bool bolSingleLine)
        {
            if (intWidth < 10 && !bolSingleLine)
                return null ;

			if (bolSingleLine) intWidth = Screen.PrimaryScreen.WorkingArea.Width;

            /// - measure height or required return bitmap
            ///    - scan list
            ///    - all images on same height from top of bitmap will be placed on a line common to each word bitmap's bottom edge
            ///    - measure width of sum of word images that fit onto a single line
            ///    - for each line, keep track of the tallest word-image
            ///      vars:
            ///         int bottomedge of previous line
            ///         int tallest word-image on this line
            ///            -> bottomedge of this line = bottomEdgeOfPrevLine + tallestWordImageOnThisLine
            /// - draw words onto bmp  
            /// 
            if (cWordArray == null || cWordArray.Length == 0)
                return null;
            int intVerticalLineGap = 5;
			int intMeasuredWidth = 0;
            bool bolLastWordVtab = false;
            for (int intWordCounter = 0; intWordCounter < cWordArray.Length; intWordCounter++)
            {
				if (udrLines.Length > 0)
				{
					if (udrLines[udrLines.Length - 1].intWidth + 20 > intMeasuredWidth)
						intMeasuredWidth = udrLines[udrLines.Length - 1].intWidth + 20;
				}
                if (cWordArray[intWordCounter].eWordImageType == enuWordImageType.vTab )
                {
                    bolLastWordVtab = true;
                    Array.Resize<classWordImageLine>(ref udrLines, udrLines.Length + 1);
                    udrLines[udrLines.Length - 1] = new classWordImageLine();
                    udrLines[udrLines.Length - 1].Word = new classWordImage[1];
                    udrLines[udrLines.Length - 1].Word[0] = cWordArray[intWordCounter];
                    udrLines[udrLines.Length - 1].intWidth = 0;
                    udrLines[udrLines.Length - 1].intBottomEdgePos = udrLines[udrLines.Length - 1].intHeight = (udrLines.Length > 1) ? udrLines[udrLines.Length - 2].intBottomEdgePos + intVTab : intVTab;                    
                }
                else if((cWordArray[intWordCounter].myPosRelToPrev == enuWordPositionRelativeToPreviousWord.NL 
                            && (!bolLastWordVtab
                                || cWordArray[intWordCounter].eWordImageType == enuWordImageType.image))
                    || (udrLines != null
                        && udrLines.Length > 0
                        && udrLines[udrLines.Length - 1].intWidth 
                            + wordSize(cWordArray[intWordCounter]).Width
                            > intWidth))
                {  // create a new line
					bolLastWordVtab = false;
                    Array.Resize<classWordImageLine>(ref udrLines, udrLines.Length + 1);
                    udrLines[udrLines.Length - 1] = new classWordImageLine();
                    udrLines[udrLines.Length - 1].Word = new classWordImage[1];
                    udrLines[udrLines.Length - 1].Word[0] = cWordArray[intWordCounter];
                    if (cWordArray[intWordCounter].eWordImageType == enuWordImageType.image)
                    {
                        double dblAspectRatio = (double)cWordArray[intWordCounter].bmp.Height / (double)wordSize( cWordArray[intWordCounter]).Width;
                        udrLines[udrLines.Length -1].intWidth = (intWidth - 10 >wordSize( cWordArray[intWordCounter]).Width) ?wordSize( cWordArray[intWordCounter]).Width : intWidth - 10;
                        
                        // create image for caption given the width of the image when displayed on this form.
                        classWordImage[] cCaptionArray = new classWordImage[0];

                        appendArrayWordImage(ref cCaptionArray,
                                                 cWordArray[intWordCounter].strText,
                                             new classMyFont(new Font("ms sans-serif", 10), Color.Gray),
                                                 enuWordPositionRelativeToPreviousWord.NL, 
                                                 enuScript.normal, 
                                                 enuWordImageType.plain);
                        classWordImageLine[] udrCaptionLines = new classWordImageLine[0];
                        cWordArray[intWordCounter].bmpCaption = putImageArrayOntoBitmap(udrLines[udrLines.Length - 1].intWidth, cCaptionArray, ref udrCaptionLines);
                        udrLines[udrLines.Length - 1].intHeight = (int)(udrLines[udrLines.Length - 1].intWidth * dblAspectRatio) 
                                                                + cWordArray[intWordCounter].bmpCaption.Height 
                                                                + intVerticalLineGap;
                        cWordArray[intWordCounter].intBaseline = udrLines[udrLines.Length - 1].intHeight;
                        udrLines[udrLines.Length - 1].intBottomEdgePos = (udrLines.Length > 1 ?
                                                udrLines[udrLines.Length - 2].intBottomEdgePos + udrLines[udrLines.Length - 1].intHeight
                                                : 
                                                udrLines[udrLines.Length - 1].intHeight);

                       // debug-here -> line width of next line is in error after an image
                        Array.Resize<classWordImageLine>(ref udrLines, udrLines.Length + 1);
                        udrLines[udrLines.Length - 1] = new classWordImageLine();
                        udrLines[udrLines.Length - 1].Word = new classWordImage[0];
                        udrLines[udrLines.Length - 1].intBottomEdgePos = (udrLines.Length > 1 ?
                                                udrLines[udrLines.Length - 2].intBottomEdgePos + udrLines[udrLines.Length - 1].intHeight
                                                :
                                                udrLines[udrLines.Length - 1].intHeight);
                    }
                    else
                    {
                       udrLines[udrLines.Length - 1].intWidth =wordSize( cWordArray[intWordCounter]).Width;
                        udrLines[udrLines.Length - 1].intHeight = cWordArray[intWordCounter].intBaseline + intVerticalLineGap;
                        udrLines[udrLines.Length - 1].intBottomEdgePos = (udrLines.Length > 1 ? 
                                                                                                udrLines[udrLines.Length - 2].intBottomEdgePos 
                                                                                                : 
                                                                                                0)
                                                                            + udrLines[udrLines.Length - 1].intHeight;
                    }
                }
                else
                { // add this word to the current line
                    bolLastWordVtab = false;
					if (udrLines.Length ==0)
					{
						udrLines = new classWordImageLine[1];
						udrLines[0] = new classWordImageLine();
						udrLines[0].Word = new classWordImage[0];
					}
                    udrLines[udrLines.Length - 1].intWidth += wordSize(cWordArray[intWordCounter]).Width;
                    
                    if (udrLines[udrLines.Length - 1].intHeight + intVerticalLineGap < cWordArray[intWordCounter].intBaseline)
                    {
                        udrLines[udrLines.Length - 1].intHeight = cWordArray[intWordCounter].intBaseline + intVerticalLineGap;
                        udrLines[udrLines.Length - 1].intBottomEdgePos = (udrLines.Length > 1 ? udrLines[udrLines.Length - 2].intBottomEdgePos : 0)
                                                                        + udrLines[udrLines.Length - 1].intHeight;
                    }
                    udrLines[udrLines.Length - 1].bolHasSubscript = udrLines[udrLines.Length - 1].bolHasSubscript || (cWordArray[intWordCounter].script == enuScript.sub);
                    udrLines[udrLines.Length - 1].bolHasSuperscript = udrLines[udrLines.Length - 1].bolHasSuperscript || (cWordArray[intWordCounter].script == enuScript.super);

                    Array.Resize<classWordImage>(ref udrLines[udrLines.Length - 1].Word, udrLines[udrLines.Length - 1].Word.Length + 1);
                    udrLines[udrLines.Length - 1].Word[udrLines[udrLines.Length - 1].Word.Length - 1] = cWordArray[intWordCounter];
                }
            }

			if (bolSingleLine) intWidth = intMeasuredWidth;
            Bitmap bmp = new Bitmap(intWidth,
                                    udrLines[udrLines.Length - 1].intBottomEdgePos
                                      + (udrLines[udrLines.Length - 1].bolHasSubscript ? (int)(udrLines[udrLines.Length - 1].intHeight * .3) : 0)
                                      + (udrLines[udrLines.Length - 1].bolHasSubscript ? (int)(udrLines[udrLines.Length - 1].intHeight * .3) : 0)
                                      + 25);

            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.FillRectangle(new SolidBrush(clrBackground), new Rectangle(0, 0, bmp.Width, bmp.Height));
                for (int intLineCounter = 0; intLineCounter < udrLines.Length; intLineCounter++)
                {
                    int intLeftNextWord = 0;
                    for (int intWordCounter = 0; intWordCounter < udrLines[intLineCounter].Word.Length; intWordCounter++)
                    {
                        int intDestTop = udrLines[intLineCounter].intBottomEdgePos - udrLines[intLineCounter].Word[intWordCounter].intBaseline;
                        udrLines[intLineCounter].Word[intWordCounter].intLine = udrLines[intLineCounter].intBottomEdgePos;
                        if (udrLines[intLineCounter].Word[intWordCounter].eWordImageType == enuWordImageType.image)
                        {
                            Size szWord = wordSize(udrLines[intLineCounter].Word[intWordCounter]);
                            double dblAspectRatio = (double)szWord.Height / (double)szWord.Width;

                            int intImageWidth = (bmp.Width -10 >szWord.Width)? szWord.Width : bmp.Width - 10;
                            udrLines[intLineCounter].Word[intWordCounter].pt = new Point((bmp.Width - intImageWidth )/2, intDestTop);
                            int intImageHeight = (int)(intImageWidth * dblAspectRatio);
                            
                            Rectangle rectDest = new Rectangle(udrLines[intLineCounter].Word[intWordCounter].pt.X, udrLines[intLineCounter].Word[intWordCounter].pt.Y, intImageWidth, intImageHeight);
                            Rectangle rectSrc = new Rectangle(0, 0, szWord.Width , szWord.Height);
                            g.DrawImage(udrLines[intLineCounter].Word[intWordCounter].bmp,
                                        rectDest,
                                        rectSrc,
                                        GraphicsUnit.Pixel);
                            rectDest = new Rectangle(udrLines[intLineCounter].Word[intWordCounter].pt.X,
                                                     udrLines[intLineCounter].Word[intWordCounter].pt.Y + intImageHeight, 
                                                     udrLines[intLineCounter].Word[intWordCounter].bmpCaption.Width, 
                                                     udrLines[intLineCounter].Word[intWordCounter].bmpCaption.Height);
                            rectSrc = new Rectangle(0,
                                                    0,
                                                    udrLines[intLineCounter].Word[intWordCounter].bmpCaption.Width, 
                                                    udrLines[intLineCounter].Word[intWordCounter].bmpCaption.Height);
                            g.DrawImage(udrLines[intLineCounter].Word[intWordCounter].bmpCaption,
                                        rectDest,
                                        rectSrc,
                                        GraphicsUnit.Pixel);
                                       
                            intDestTop = udrLines[intLineCounter].Word[intWordCounter].pt.Y + intImageHeight + rectDest.Height;
                           
                        }
                        else
                        {
                            switch (udrLines[intLineCounter].Word[intWordCounter].script)
                            {
                                case enuScript.super:
                                    if (intWordCounter > 0)
                                        intDestTop = udrLines[intLineCounter].intBottomEdgePos
                                                    - udrLines[intLineCounter].Word[intWordCounter - 1].bmp.Height
                                                    - (int)(udrLines[intLineCounter].Word[intWordCounter].bmp.Height * .5);
                                    break;

                                case enuScript.sub:
                                    intDestTop = udrLines[intLineCounter].intBottomEdgePos
                                                - (int)(udrLines[intLineCounter].Word[intWordCounter].fnt.fnt.Size * 1.5);
                                    break;
                            }
                            if (udrLines[intLineCounter].Word[intWordCounter].eWordImageType == enuWordImageType.hTab)
                            {
                                intLeftNextWord += intHTab;
                                udrLines[intLineCounter].Word[intWordCounter].pt = new Point(intLeftNextWord, intDestTop);
                            }
                            else if (udrLines[intLineCounter].Word[intWordCounter].eWordImageType == enuWordImageType.vTab)
                            {
                                udrLines[intLineCounter].Word[intWordCounter].pt = new Point(intLeftNextWord, intDestTop);
                                udrLines[intLineCounter].intBottomEdgePos = (intLineCounter > 0) ? udrLines[intLineCounter - 1].intBottomEdgePos + intVTab : intVTab;
                            }
                            else
                            {
                                Rectangle rectDest = new Rectangle(intLeftNextWord, intDestTop, udrLines[intLineCounter].Word[intWordCounter].bmp.Width, udrLines[intLineCounter].Word[intWordCounter].bmp.Height);
                                Rectangle rectSrc = new Rectangle(0, 0, udrLines[intLineCounter].Word[intWordCounter].bmp.Width, udrLines[intLineCounter].Word[intWordCounter].bmp.Height);
								
                                g.DrawImage(udrLines[intLineCounter].Word[intWordCounter].bmp,
                                            rectDest,
                                            rectSrc,
                                            GraphicsUnit.Pixel);
                                
                                udrLines[intLineCounter].Word[intWordCounter].pt = rectDest.Location;

                                int intItalicLeftShift = udrLines[intLineCounter].Word[intWordCounter].fnt.fnt.Italic
                                    ? (int)((double)udrLines[intLineCounter].Word[intWordCounter].fnt.fnt.Size * .5)
                                    : 0;
                                intLeftNextWord += udrLines[intLineCounter].Word[intWordCounter].bmp.Width - intItalicLeftShift;
                            }
                        }
                    }
                }
            }
            return bmp;
        }
    }
    public enum enuScript { normal, super, sub }
    public struct udtWordImageSearchData
    {
        public classWordImage right;
        public classWordImage left;
        public classWordImage next;
    }

    /// <summary>
    /// word image description including text, position relative to previous word on page, font, and pt (the image's location on final bitmap used by getWordUnderMouse())
    /// </summary>
    public enum enuWordImageType { 
        plain,                  // 
        link,                   // underlined text causes mouse cursor to change -> linked to strAddress controlled by main form
        image,                   // flexible image size, takes up its own line, maintains aspect-ratio but grows to fit containing panel
        solution,               // like a link but pops up 'strAddress' as text 
        flash,
        vTab,
        hTab
    }

    public class classWordImage
    {
        public Bitmap bmp;
        public Bitmap bmpCaption;
        public enuWordImageType eWordImageType;
        public enuWordPositionRelativeToPreviousWord myPosRelToPrev; 
        public classMyFont fnt;
        public string strText;
        public string strAddress;
        public int intBaseline;           // top of image relative to the horizontal line common to all images on the same line of text on output bitmap
        public int intLine;            // y-component on which 'bottom line edge' is common to every word on this line pt.y = intBottomEdgePos - intBaseline
        public enuScript script;
        public udtWordImageSearchData Search;  // bin-tree search fields
        public Point pt;                       // position of this word's bitmap on the output image
        static int intUniqueIDCounter = 0;
        public int intUniqueID;
        public classWordImage()
        {
            intUniqueID = intUniqueIDCounter++;
        }
    }

    /// <summary>
    /// font with forecolor variable
    /// </summary>
    public class classMyFont
    {
        public Font fnt;
        public Color foreColor;

        public classMyFont(Font fntNew, Color clr)
        {
            fnt = fntNew;
            foreColor = clr;
        }
    }

    
    /// <summary>
    /// panel with image controlled by vertical scroll bar
    /// </summary>
    public class Panel_GraphicText : Panel
    {
        public VScrollBar vsb = new VScrollBar();
        int intOverHead = 5;
        public PictureBox pic = new PictureBox();
        classGraphicText cLibGrText;
        public classWordImage[] cWordArray;
        public string strTitle = "Search Results : ";
        public Point ptMouse;
        public bool bolQuitOnEscape = false;
       public  TextBox txtControls = new TextBox();
	   
        int intPicWidth_Narrow = 0;
        int intPicWidth_Wide = 0;

        public Panel_GraphicText()
        {
            Controls.Add(pic);
            pic.Visible = true;
            pic.Location = new Point(0, 0);
            BackColor = Color.White;

            Controls.Add(vsb);
            vsb.Maximum = 1000;

            Controls.Add(txtControls);
            txtControls.Top = -100;
            txtControls.KeyDown += new KeyEventHandler(txtControls_KeyDown);
            txtControls.MouseWheel += new MouseEventHandler(_MouseWheel);
            pic.GotFocus += new EventHandler(pic_GotFocus);

            cWordArray = new classWordImage[0];
            intPicWidth_Wide = Width -5;
            intPicWidth_Narrow = intPicWidth_Wide - vsb.Width;
            vsb.ValueChanged += new EventHandler(vsb_ValueChanged);
            SizeChanged += new EventHandler(Form_GraphicText_SizeChanged);
            MouseWheel += new MouseEventHandler(_MouseWheel);
            pic.MouseWheel += new MouseEventHandler(_MouseWheel);
            pic.MouseMove += new MouseEventHandler(pic_MouseMove);

            Text = strTitle;
            cLibGrText = new classGraphicText();            
        }

        
        void pic_GotFocus(object sender, EventArgs e)
        {
            txtControls.Focus();
        }

        void txtControls_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Escape:
                    break;
            }
        }

        public Color textBackGround
        {
            get
            {
				return GraphicText.classGraphicText.clrBackground;
            }
            set
            {
				GraphicText.classGraphicText.clrBackground = value;
            }
        }

        void pic_MouseMove(object sender, MouseEventArgs e)
        {
            ptMouse = new Point(e.X, e.Y);
        }

        /// <summary>
        /// returns the classWordImage located beneath the current mousepointer on the picbox's image 
        /// </summary>
        /// <returns>classWordImage beneath the mouse or null if none found</returns>
        public classWordImage getWordUnderMouse()
        {
            
            int intStepSize = cWordArray.Length;
            int intIndex = 0;
            while (intStepSize > 1 && intIndex < cWordArray.Length && intIndex >= 0)
            {
                intStepSize = (int)Math.Ceiling((double)intStepSize / 2);
                if (ptMouse.Y > cWordArray[intIndex].pt.Y + cWordArray[intIndex].intBaseline)
                    intIndex += intStepSize;
                else if (ptMouse.Y < cWordArray[intIndex].pt.Y)
                    intIndex -= intStepSize;
                else
                    break;
            }

            int intDir = -1;
            if (intIndex >= 0 && intIndex < cWordArray.Length)
            {

                if (ptMouse.X > cWordArray[intIndex].pt.X)
                    intDir = 1;
                int intThisDir = 0;

                while (intIndex >= 0
                        && intIndex < cWordArray.Length)
                {
                    if (ptMouse.X > cWordArray[intIndex].pt.X + cWordArray[intIndex].bmp.Width)
                        intThisDir = 1;
                    else if (ptMouse.X < cWordArray[intIndex].pt.X)
                        intThisDir = -1;
                    else
                    {
                        if (ptMouse.X > cWordArray[intIndex].pt.X
                            && ptMouse.X < cWordArray[intIndex].pt.X + cWordArray[intIndex].bmp.Width
                            && ptMouse.Y > cWordArray[intIndex].pt.Y
                            && ptMouse.Y < cWordArray[intIndex].pt.Y + cWordArray[intIndex].bmp.Height)
                        {
                            return cWordArray[intIndex];
                        }
                    }
                    if (intDir != intThisDir)
                        return null;
                    else
                        intIndex += intThisDir;
                }
            }

            return null;
        }

        public void _MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta > 0)
            {
                if (vsb.Value - vsb.SmallChange >= vsb.Minimum)
                    vsb.Value -= vsb.SmallChange;
                else
                    vsb.Value = vsb.Minimum;
            }
            else
            {
                if (vsb.Value + vsb.SmallChange <= vsb.Maximum - vsb.LargeChange)
                    vsb.Value += vsb.SmallChange;
                else
                    vsb.Value = vsb.Maximum - vsb.LargeChange;
            }
        }

        
        public void setTitle(string strText)
        {
            Text = strTitle + "\"" + strText + "\"";
        }

        public void Form_GraphicText_SizeChanged(object sender, EventArgs e)
        {
            setVSB();
            intPicWidth_Wide = Width - 5;
            intPicWidth_Narrow = vsb.Left;

            if (vsb.Visible)
                pic.Width = intPicWidth_Narrow;
            else
                pic.Width = intPicWidth_Wide;
            putWordArrayToScreen();
        }

        void setVSB()
        {
            vsb.Height = Height - vsb.Top - intOverHead;
            if (vsb.Height < 1)
                return;
            try
            {
                vsb.Top = 5;
                vsb.Left = Width - vsb.Width;

                vsb.Visible = (pic.Height > Height - intOverHead);
                vsb.LargeChange = (int)(((double)(Height - intOverHead) / (double)pic.Height) * 1000.0);
                if (vsb.LargeChange > vsb.Maximum)
                    vsb.LargeChange = vsb.Maximum;
                vsb.SmallChange = (int)Math.Ceiling((double)vsb.LargeChange / 8.0);

                vsb.Value = 0;
            }
            catch (Exception) { }
        }

        void vsb_ValueChanged(object sender, EventArgs e)
        {
            int intHighest = Height - intOverHead - pic.Height;
            int intLowest = 0;

            int intDifference = (intHighest - intLowest);
            if (vsb.Maximum == vsb.LargeChange)
                pic.Top = 0;
            else
            {
                double dblRatio = (double)vsb.Value / (double)(vsb.Maximum - vsb.LargeChange);
                pic.Top = (int)((double)intDifference * dblRatio);
            }
        }
		
        public void putWordArrayToScreen()
        {
            int intWidthPic = intPicWidth_Wide;

            startPutWordArrayToScreen:

			Bitmap bmp = GraphicText.classGraphicText.putImageArrayOntoBitmap(intWidthPic, cWordArray);
            if (bmp != null)
            {
                pic.Size = bmp.Size;
                pic.Image = bmp;
                pic.BringToFront();
                pic.Visible = true;
                setVSB();

                if (vsb.Visible && pic.Width == intPicWidth_Wide)
                {
                    intWidthPic = intPicWidth_Narrow;
                    goto startPutWordArrayToScreen;
                }
            }
            Visible = true;
            vsb.Value = 0;
            BringToFront();
        }
    }


    /// <summary>
    /// form with panel_graphic_text, image & vertical scroll bar
    /// </summary>
    public class Form_GraphicText : Form
    {
        bool bolInit = false;
        public Panel_GraphicText pnl;
        public bool bolQuitOnEscape = false;
        
        public Form_GraphicText()
        {
            Visible = false;
            pnl = new Panel_GraphicText();
            Controls.Add(pnl);
            pnl.Dock = DockStyle.Fill;

            bolQuitOnEscape = true;

            Activated += new EventHandler(Form_GraphicText_Activated);
            KeyDown += new KeyEventHandler(Form_GraphicText_KeyDown);
            Opacity = 1.0;
        }

        void Form_GraphicText_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    break;

                case Keys.Escape:
                    if (bolQuitOnEscape)
                        Dispose();
                    break;
            }

        }
        void Form_GraphicText_Activated(object sender, EventArgs e)
        {
            if (!bolInit)
            {
                bolInit = true;
                Size = new Size(400, 600);
                Location = new Point(0, 0);
            }
        }

    }
}

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

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

License

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


Written By
CEO unemployable
Canada Canada
Christ Kennedy grew up in the suburbs of Montreal and is a bilingual Quebecois with a bachelor’s degree in computer engineering from McGill University. He is unemployable and currently living in Moncton, N.B. writing his next novel.

Comments and Discussions