示例#1
0
    public void LoadText(SystemLanguage language)
    {
        TextAsset textAsset = (TextAsset)Resources.Load(GetResourcePath(language), typeof(TextAsset));

        mTextItems = Serialization.DeserialiseFromTextAsset <TextItems>(textAsset);

        // Add items to dictionary
        foreach (TextItem item in mTextItems.Items)
        {
            if (mTextManagerItems.ContainsKey(item.Id))
            {
                Debug.LogError("TextManager.LoadText - we already have an item with Id " + item.Id);
            }
            mTextManagerItems[item.Id] = new List <UsedTextItem>();//new Dictionary<string, bool>();

            if (TestCoverage == true)
            {
                // text coverage mode.
                mTextManagerItems[item.Id].Add(new UsedTextItem("xxxxxxxxxxxxxx"));
            }
            else
            {
                // normal case, just as it used to be
                foreach (string text in item.GetList())
                {
                    mTextManagerItems[item.Id].Add(new UsedTextItem(text));
                }
            }
        }
    }
        /// <summary>
        /// Метод для отрисовки расписания
        /// </summary>
        private void DrawSchedule()
        {
            var machines      = (Schedule ?? throw new ArgumentNullException()).Select(m => m.Machine).Distinct().OrderBy(m => m.Name).ToList();
            var y             = 10;
            var timeLinePoint = 0;

            foreach (var machine in machines)
            {
                TextItems.Add(new TextDetails(10, y - 35, 50, 50, machine.Name));
                RectItems.Add(new RectItem(10, y, 50, 50, "Black"));
                var batches = Schedule.Where(m => m.Machine.Id == machine.Id).Select(b => b.Batch).ToList();
                var x       = 65;
                foreach (var b in batches)
                {
                    var color = b.NomenclatureId switch
                    {
                        0 => "Gold",
                        1 => "Silver",
                        2 => "LightSteelBlue",
                        _ => "Black"
                    };
                    timeLinePoint += machine.TimeDictionary[b.NomenclatureId];
                    var widthFromTime = machine.TimeDictionary[b.NomenclatureId] + 15;
                    TextItems.Add(new TextDetails(x + widthFromTime, y + 32, 20, 20, timeLinePoint.ToString()));
                    TextItems.Add(new TextDetails(x, y, widthFromTime, 20, b.Nomenclature.Name.Substring(0, 3)));
                    RectItems.Add(new RectItem(x, y, widthFromTime, 50, color));
                    x += widthFromTime + 2;
                }
                TimeLines.Add(new TimeLine(10, y + 23, x + 10, y + 23));
                y            += 90;
                timeLinePoint = 0;
            }
        }
    }
示例#3
0
 /// <summary>
 /// create new SubtitleText from initial string
 /// </summary>
 /// <param name="initialText"></param>
 public SubtitleText(string initialText)
     : this()
 {
     TextItems.Add(initialText);
     TextDurations.Add(1);
     doReplace = true;
     InitFont();
 }
示例#4
0
        public void TextGet()
        {
            TestUtils.Upload(c_fileName, c_folderName + "/" + c_fileName);
            TextItems presentationItems          = TestUtils.SlidesApi.GetPresentationTextItems(c_fileName, null, c_password, c_folderName);
            TextItems presentationItemsWithEmpty = TestUtils.SlidesApi.GetPresentationTextItems(c_fileName, true, c_password, c_folderName);
            TextItems slideItems          = TestUtils.SlidesApi.GetSlideTextItems(c_fileName, c_slideIndex, null, c_password, c_folderName);
            TextItems slideItemsWithEmpty = TestUtils.SlidesApi.GetSlideTextItems(c_fileName, c_slideIndex, true, c_password, c_folderName);

            Assert.Less(presentationItems.Items.Count, presentationItemsWithEmpty.Items.Count);
            Assert.Less(slideItems.Items.Count, presentationItems.Items.Count);
            Assert.Less(slideItems.Items.Count, slideItemsWithEmpty.Items.Count);
        }
示例#5
0
 /// <summary>
 /// create a new multitext, with multiple strings showing at indicated times.
 /// </summary>
 /// <param name="multiText"></param>
 /// <param name="timings">per multiText item, number of seconds that this item should display</param>
 /// <param name="doReplace">if true, only latest item from multiText is displayed.
 ///                         If false, each item is added to the previous one.</param>
 public SubtitleText(string[] multiText, float[] timings, bool doReplace)
 {
     foreach (var t in multiText)
     {
         TextItems.Add(t);
     }
     foreach (var t in timings)
     {
         TextDurations.Add(t);
     }
     this.doReplace = doReplace;
     InitFont();
 }
        private void AddTocToHtm()
        {
            TextItems.Add(new TextItem
            {
                Content     = TocCaption,
                LogicalType = TextItemType.H1
            });

            foreach (var ti in StructuredText.TextItems)
            {
                // ReSharper disable once SwitchStatementMissingSomeCases
                switch (ti.LogicalType)
                {
                case TextItemType.H1:
                    if (TocLevel > 0)
                    {
                        _rowCount++;
                    }
                    break;

                case TextItemType.H2:
                    if (TocLevel > 1)
                    {
                        _rowCount++;
                    }
                    break;

                case TextItemType.H3:
                    if (TocLevel > 2)
                    {
                        _rowCount++;
                    }
                    break;

                case TextItemType.H4:
                    if (TocLevel > 3)
                    {
                        _rowCount++;
                    }
                    break;
                }
            }

            _rowCount++;

            var row = -1;

            foreach (var ti in StructuredText.TextItems)
            {
                row++;

                // ReSharper disable once SwitchStatementMissingSomeCases
                switch (ti.LogicalType)
                {
                case TextItemType.H1:
                    if (TocLevel > 0)
                    {
                        //Debug.Print("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n",
                        //    ti.Content, _rowCount,
                        //    CssToc1);
                        TextItems.Add(new TextItem
                        {
                            Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n",
                                                    ti.Content, row + _rowCount + 1,
                                                    CssToc1),
                            LogicalType = TextItemType.Plain
                        });
                    }

                    break;

                case TextItemType.H2:
                    if (TocLevel > 1)
                    {
                        TextItems.Add(new TextItem
                        {
                            Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n",
                                                    ti.Content, row + _rowCount + 1,
                                                    CssToc2),
                            LogicalType = TextItemType.Plain
                        });
                    }
                    break;

                case TextItemType.H3:
                    if (TocLevel > 2)
                    {
                        TextItems.Add(new TextItem
                        {
                            Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n",
                                                    ti.Content, row + _rowCount + 1,
                                                    CssToc3),
                            LogicalType = TextItemType.Plain
                        });
                    }
                    break;

                case TextItemType.H4:
                    if (TocLevel > 3)
                    {
                        TextItems.Add(new TextItem
                        {
                            Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n",
                                                    ti.Content, row + _rowCount + 1,
                                                    CssToc4),
                            LogicalType = TextItemType.Plain
                        });
                    }
                    break;
                }
            }

            foreach (var ti in StructuredText.TextItems)
            {
                TextItems.Add(ti);
            }
        }
            // This article provides a real-world tutorial of how to actually use the API, including
            // a discussion of many gotchas not identified in the MSDN documentation.
            // http://www.catch22.net/tuts/uniscribe-mysteries
            // http://www.catch22.net/tuts/more-uniscribe-mysteries
            // http://www.catch22.net/tuts/drawing-styled-text-uniscribe
            // From the developer of Google Chrome's uniscribe client:
            // https://maxradi.us/documents/uniscribe/
            // Arabic embedded (RTL) example:
            // http://blogs.msdn.com/b/vsarabic/archive/2011/08/21/text-rendering.aspx
            // Devanagari example:
            // http://www.omniglot.com/language/articles/devanagari.htm
            // UTF16 non-zero plane exahere:
            // https://en.wikipedia.org/wiki/UTF-16#Examples
            // http://www.i18nguy.com/unicode-example-plane1.html
            // "Displaying Text with Uniscribe"
            // https://msdn.microsoft.com/en-us/library/windows/desktop/dd317792%28v=vs.85%29.aspx
            internal static TextItems AnalyzeText(
                TextServiceUniscribe service,
                IntPtr hdc,
                IntPtr hText,
                FontRunInfo[] fontRuns)
            {
                TextItems o = new TextItems(service);
                try
                {

                    o.fontRuns = fontRuns;
                    for (int i = 0; i < fontRuns.Length; i++)
                    {
                        o.count += fontRuns[i].count;
                        o.lineHeight = Math.Max(o.lineHeight, fontRuns[i].fontHeight);
                    }
                    if (o.count == 0)
                    {
                        return o;
                    }

                    int hr;

                    // Lay Out Text Using Uniscribe

                    // 1. Call ScriptRecordDigitSubstitution only when starting or when receiving a WM_SETTINGCHANGE message.

                    // 2. (Optional) Call ScriptIsComplex to determine if the paragraph requires complex processing.
                    hr = ScriptIsComplex(
                        hText,
                        o.count,
                        ScriptIsComplexFlags.SIC_ASCIIDIGIT | ScriptIsComplexFlags.SIC_COMPLEX);
                    if (hr < 0)
                    {
                        Marshal.ThrowExceptionForHR(hr);
                    }
                    // Optional: if S_FALSE (1) is returned, one can fall back to TextRenderer and simplified hit testing

                    // 3. (Optional) If using Uniscribe to handle bidirectional text and/or digit substitution, call
                    // ScriptApplyDigitSubstitution to prepare the SCRIPT_CONTROL and SCRIPT_STATE structures as inputs
                    // to ScriptItemize. If skipping this step, but still requiring digit substitution, substitute
                    // national digits for Unicode U+0030 through U+0039 (European digits). For information about digit
                    // substitution, see Digit Shapes.
                    hr = ScriptApplyDigitSubstitution(
                        IntPtr.Zero,
                        out o.sControl,
                        out o.sState);
                    if (hr < 0)
                    {
                        Marshal.ThrowExceptionForHR(hr);
                    }

                    // 4. Call ScriptItemize to divide the paragraph into items. If not using Uniscribe for digit
                    // substitution and the bidirectional order is known, for example, because of the keyboard layout
                    // used to enter the character, call ScriptItemize. In the call, provide null pointers for the
                    // SCRIPT_CONTROL and SCRIPT_STATE structures. This technique generates items by use of the shaping
                    // engine only, and the items can be reordered using the engine information.
                    // Note: Typically, applications that work only with left-to-right scripts and without any digit
                    // substitution should pass null pointers for the SCRIPT_CONTROL and SCRIPT_STATE structures.

                    {
                        int cMaxItems = 8;
                        SCRIPT_ITEM[] sItems;
                        OPENTYPE_TAG[] sTags;
                        while (true)
                        {
                            sItems = new SCRIPT_ITEM[cMaxItems + 1]; // method adds terminator;
                            sTags = new OPENTYPE_TAG[cMaxItems];
                            hr = ScriptItemizeOpenType(
                                hText,
                                o.count,
                                cMaxItems,
                                ref o.sControl,
                                ref o.sState,
                                sItems,
                                sTags,
                                out o.cItems);
                            if (hr == E_OUTOFMEMORY)
                            {
                                cMaxItems *= 2;
                                continue;
                            }
                            if (hr < 0)
                            {
                                Marshal.ThrowExceptionForHR(hr);
                            }
                            break;
                        }

                        o.sItems = sItems;
                        o.sTags = sTags;
                    }

                    // 5. Merge the item information with the run information to produce ranges.
                    {
                        int fontRunOffset = 0;
                        int f = 0;
                        int i = 0;
                        while ((f < o.fontRuns.Length) && (i < o.cItems))
                        {
                            if (fontRunOffset + o.fontRuns[f].count > o.sItems[i + 1].iCharPos)
                            {
                                // run is longer - current item remains intact; advance to next
                                i++;
                                continue;
                            }
                            else if (fontRunOffset + o.fontRuns[f].count < o.sItems[i + 1].iCharPos)
                            {
                                // item too long - split

                                Array.Resize(ref o.sItems, o.cItems + 1 + 1);
                                Array.Copy(o.sItems, i, o.sItems, i + 1, o.sItems.Length - (i + 1));
                                Array.Resize(ref o.sTags, o.cItems + 1);
                                Array.Copy(o.sTags, i, o.sTags, i + 1, o.sTags.Length - (i + 1));
                                o.cItems++;

                                o.sItems[i + 1].iCharPos = fontRunOffset + o.fontRuns[f].count;
                            }
                            Debug.Assert(fontRunOffset + o.fontRuns[f].count == o.sItems[i + 1].iCharPos);
                            fontRunOffset += o.fontRuns[f].count;
                            f++;
                            i++;
                        }
                        Debug.Assert(fontRunOffset == o.count);
                        Debug.Assert(o.sItems[o.cItems].iCharPos == o.count);
                    }

                    // 6. Call ScriptShape to identify clusters and generate glyphs.
                    o.sItemsExtra = new ItemInfo[o.cItems];
                    o.logAttrs = new SCRIPT_LOGATTR[o.count];
                    for (int i = 0; i < o.cItems; i++)
                    {
                        int start = o.sItems[i].iCharPos;
                        int length = o.sItems[i + 1].iCharPos - start;

                        Font font = null;
                        for (int f = 0, pos = 0; f < o.fontRuns.Length; pos += o.fontRuns[f].count, f++)
                        {
                            font = o.fontRuns[f].font;
                            if (pos < start + length)
                            {
                                break;
                            }
                        }

                        int cMaxGlyphs = (3 * o.count / 2) + 16; // recommended starting value
                        short[] glyphs;
                        short[] logicalClusters;
                        SCRIPT_VISATTR[] visAttrs; // superceded by glyphProps
                        SCRIPT_GLYPHPROP[] glyphProps;
                        int cGlyphs;
                        int fallbackLevel = 0;
                        Font fallbackFont = null;
                        SCRIPT_CHARPROP[] charProps = new SCRIPT_CHARPROP[length];
                        while (true)
                        {
                            glyphs = new short[cMaxGlyphs];
                            logicalClusters = new short[cMaxGlyphs];
                            visAttrs = new SCRIPT_VISATTR[cMaxGlyphs];
                            glyphProps = new SCRIPT_GLYPHPROP[cMaxGlyphs];

                            bool needFallback = false;
                            int fontCacheIndex = service.FontCacheIndex(font);

                            GDIFont gdiFont;
                            if (!service.fontToHFont.TryGetValue(font, out gdiFont))
                            {
                                gdiFont = new GDIFont(font);
                                service.fontToHFont.Add(font, gdiFont);
                            }
                            GDI.SelectObject(hdc, gdiFont);

                #if false // choose old or OpenType API
                        hr = ScriptShape(
                            hdc,
                            ref service.caches[fontCacheIndex].cache,
                            new IntPtr(hText.ToInt64() + start * 2),
                            length,
                            cMaxGlyphs,
                            ref o.sItems[i].a,
                            glyphs,
                            logicalClusters,
                            visAttrs,
                            out cGlyphs);
                #else
                            hr = ScriptShapeOpenType(
                                hdc,
                                ref service.caches[fontCacheIndex].cache,
                                ref o.sItems[i].a,
                                o.sTags[i], // tagScript
                                o.sTags[i], // tagLangSys -- right thing to pass here?
                                null, // rcRangeChars
                                null, // rpRangeProperties
                                0, // cRanges
                                new IntPtr(hText.ToInt64() + start * 2),
                                length,
                                cMaxGlyphs,
                                logicalClusters,
                                charProps,
                                glyphs,
                                glyphProps, // supercedes visAttrs
                                out cGlyphs);
                #endif
                            if (hr == E_OUTOFMEMORY)
                            {
                                cMaxGlyphs *= 2;
                                glyphs = new short[cMaxGlyphs];
                                logicalClusters = new short[cMaxGlyphs];
                                visAttrs = new SCRIPT_VISATTR[cMaxGlyphs];
                                continue;
                            }
                            if (hr == USP_E_SCRIPT_NOT_IN_FONT)
                            {
                                needFallback = true;
                                goto FontFallback;
                            }
                            if (hr < 0)
                            {
                                Marshal.ThrowExceptionForHR(hr);
                            }
                            // 7. If ScriptShape returns the code USP_E_SCRIPT_NOT_IN_FONT or S_OK with the output containing
                            // missing glyphs, select characters from a different font. Either substitute another font or disable
                            // shaping by setting the eScript member of the SCRIPT_ANALYSIS structure passed to ScriptShape to
                            // SCRIPT_UNDEFINED. For more information, see Using Font Fallback.
                            SCRIPT_FONTPROPERTIES sfp;
                            ScriptGetFontProperties(
                                hdc,
                                ref service.caches[fontCacheIndex].cache,
                                out sfp);
                            for (int j = 0; j < cGlyphs; j++)
                            {
                                if (glyphs[j] == sfp.wgDefault)
                                {
                                    needFallback = true;
                                    break;
                                }
                            }
                        FontFallback:
                            if (needFallback)
                            {
                                // What worked:
                                // https://code.google.com/p/chromium/codesearch#chromium/src/ui/gfx/font_fallback_win.cc&q=uniscribe&sq=package:chromium&l=283&dr=CSs
                                // http://stackoverflow.com/questions/16828868/how-to-automatically-choose-most-suitable-font-for-different-language
                                // What didn't work:
                                // The totally unhelpful Uniscribe font/script fallback documentation:
                                // https://msdn.microsoft.com/en-us/library/windows/desktop/dd374105%28v=vs.85%29.aspx
                                // MSDN Globalization how-to page about font fallback:
                                // https://msdn.microsoft.com/en-us/goglobal/bb688134.aspx
                                // ScriptShape page:
                                // https://msdn.microsoft.com/en-us/library/windows/desktop/dd368564(v=vs.85).aspx

                                fallbackLevel++;
                                switch (fallbackLevel)
                                {
                                    case 1:
                                        GDI.LOGFONT fallbackLF;
                                        if (GetUniscribeFallbackFont(
                                            font,
                                            new IntPtr(hText.ToInt64() + 2 * start),
                                            length,
                                            out fallbackLF))
                                        {
                                            fallbackFont = null;
                                            foreach (KeyValuePair<GDI.LOGFONT, Font> item in service.fallbackFonts)
                                            {
                                                if (String.Equals(item.Key.lfFaceName, fallbackLF.lfFaceName)
                                                    && (item.Key.lfCharSet == fallbackLF.lfCharSet)
                                                    && (item.Key.lfHeight == fallbackLF.lfHeight))
                                                {
                                                    fallbackFont = item.Value;
                                                    break;
                                                }
                                            }
                                            if (fallbackFont == null)
                                            {
                                                fallbackFont = Font.FromLogFont(fallbackLF);
                                                service.fallbackFonts.Add(new KeyValuePair<GDI.LOGFONT, Font>(fallbackLF, fallbackFont));
                                            }
                                            font = fallbackFont;
                                            continue;
                                        }
                                        continue;

                                    case 2:
                                        if (o.sItems[i].a.eScript != SCRIPT_UNDEFINED)
                                        {
                                            o.sItems[i].a.eScript = SCRIPT_UNDEFINED;
                                        }
                                        continue;

                                    default:
                                        // give up
                                        break;
                                }
                            }

                            break;
                        }

                        // 8. Call ScriptPlace to generate advance widths and x and y positions for the glyphs in each
                        // successive range. This is the first step for which text size becomes a consideration.
                        int[] iAdvances = new int[cGlyphs];
                        GOFFSET[] goffsets = new GOFFSET[cGlyphs];
                        ABC abc = new ABC();
                        {
                            int fontCacheIndex = service.FontCacheIndex(font);
                #if false // choose old or OpenType API
                        hr = ScriptPlace(
                            hdc,
                            ref service.caches[fontCacheIndex].cache,
                            glyphs,
                            cGlyphs,
                            visAttrs,
                            ref o.sItems[i].a,
                            iAdvances,
                            goffsets,
                            out abc);
                #else
                            hr = ScriptPlaceOpenType(
                                hdc,
                                ref service.caches[fontCacheIndex].cache,
                                ref o.sItems[i].a,
                                o.sTags[i], // tagScript
                                o.sTags[i], // tagLangSys -- right thing to pass here?
                                null, // rcRangeChars
                                null, // rpRangeProperties
                                0, // cRanges
                                new IntPtr(hText.ToInt64() + start * 2),
                                logicalClusters,
                                charProps,
                                length,
                                glyphs,
                                glyphProps,
                                cGlyphs,
                                iAdvances,
                                goffsets,
                                out abc);
                #endif
                            if (hr < 0)
                            {
                                Marshal.ThrowExceptionForHR(hr);
                            }
                        }

                        o.sItemsExtra[i].glyphs = glyphs;
                        o.sItemsExtra[i].logicalClusters = logicalClusters;
                        o.sItemsExtra[i].visAttrs = visAttrs;
                        o.sItemsExtra[i].cGlyphs = cGlyphs;
                        o.sItemsExtra[i].charProps = charProps;
                        o.sItemsExtra[i].glyphProps = glyphProps;

                        o.sItemsExtra[i].iAdvances = iAdvances;
                        o.sItemsExtra[i].goffsets = goffsets;
                        o.sItemsExtra[i].abc = abc;

                        o.sItemsExtra[i].fallbackFont = fallbackFont;

                        // 9. Sum the range sizes until the line overflows.

                        // 10. Break the range on a word boundary by using the fSoftBreak and fWhiteSpace members in the
                        // logical attributes. To break a single character cluster off the run, use the information returned
                        // by calling ScriptBreak.
                        // Note: Decide if the first code point of a range should be a word break point because the last
                        // character of the previous range requires it. For example, if one range ends in a comma, consider
                        // the first character of the next range to be a word break point.
                        SCRIPT_LOGATTR[] logAttrs1 = new SCRIPT_LOGATTR[o.count];
                        hr = ScriptBreak(
                            new IntPtr(hText.ToInt64() + 2 * start),
                            length,
                            ref o.sItems[i].a,
                            logAttrs1);
                        if (hr < 0)
                        {
                            Marshal.ThrowExceptionForHR(hr);
                        }
                        Array.Copy(logAttrs1, 0, o.logAttrs, o.sItems[i].iCharPos, length);

                        // 11. Repeat steps 6 through 10 for each line in the paragraph. However, if breaking the last run
                        // on the line, call ScriptShape to reshape the remaining part of the run as the first run on the
                        // next line.
                    }

                    // Display Text Using Uniscribe

                    // 1. For each run, do the following:
                    // a. If the style has changed since the last run, update the handle to the device context by releasing
                    //    and getting it again.
                    // b. Call ScriptShape to generate glyphs for the run.
                    // c. Call ScriptPlace to generate an advance width and an x,y offset for each glyph.

                    // 2. Do the following to establish the correct visual order for the runs in the line:
                    // a. Extract an array of bidirectional embedding levels, one per range. The embedding level is
                    //    given by (SCRIPT_ITEM) si.(SCRIPT_ANALYSIS) a. (SCRIPT_STATE) s.uBidiLevel.
                    // b. Pass this array to ScriptLayout to generate a map of visual positions to logical positions.
                    byte[] bidiEmbeddingLevels = new byte[o.cItems];
                    for (int i = 0; i < o.cItems; i++)
                    {
                        bidiEmbeddingLevels[i] = (byte)o.sItems[i].a.s.uBidiLevel;
                    }
                    o.iVisualToLogical = new int[o.cItems];
                    o.iLogicalToVisual = new int[o.cItems];
                    hr = ScriptLayout(
                        o.cItems,
                        bidiEmbeddingLevels,
                        o.iVisualToLogical,
                        o.iLogicalToVisual);
                    if (hr < 0)
                    {
                        Marshal.ThrowExceptionForHR(hr);
                    }

                    for (int i = 0; i < o.cItems; i++)
                    {
                        for (int j = 0; j < o.sItemsExtra[i].iAdvances.Length; j++)
                        {
                            o.sItemsExtra[i].totalWidth += o.sItemsExtra[i].iAdvances[j];
                        }
                    }
                }
                catch (Exception)
                {
                    o.Dispose();
                    throw;
                }

                return o;
            }
        /// <summary>
        /// Draws the graph
        /// </summary>
        private void DrawGraph()
        {
            if (CanvasHeight == 0 || CanvasWidth == 0)
            {
                return;
            }

            //clear the containers
            RectangleItems.Clear();
            LineItems.Clear();
            TextItems.Clear();
            PointCollection points = new PointCollection();

            //set some stuff
            int numPoints = 100;
            int ticks     = 8;

            //get the max an min of the efficieny points
            double maxOrd = EfficiencyMeasurements.Max(e => e.Efficiency);
            double minOrd = EfficiencyMeasurements.Min(e => e.Efficiency);

            //get ordinate graph bounds that look nice
            double ordTickRange = GetTickRange(maxOrd - minOrd, ticks);
            double ordTickMag   = Math.Log10(ordTickRange) > 0 ? Math.Ceiling(Math.Log10(ordTickRange)) : Math.Floor(Math.Log10(ordTickRange));

            maxOrd = ordTickRange * Math.Round(1 + maxOrd / ordTickRange);
            minOrd = ordTickRange * (Math.Round(minOrd / ordTickRange - 1));

            double minAbsc = 0;// Properties.Settings.Default.LOWERELIMT * 0.75;
            double maxAbsc = Properties.Settings.Default.UPPERENERGY;

            //get abscissa graph bounds that look nice
            double abscTickRange = GetTickRange(maxAbsc - minAbsc, ticks);
            double abscTickMag   = Math.Log10(abscTickRange) > 0 ? Math.Ceiling(Math.Log10(abscTickRange)) : Math.Floor(Math.Log10(abscTickRange));

            maxAbsc = abscTickRange * Math.Round(maxAbsc / abscTickRange);
            minAbsc = abscTickRange * (Math.Round(minAbsc / abscTickRange));


            int       seperation = 20;
            Rectangle chart      = new Rectangle(0.2 * CanvasWidth - seperation, seperation, (int)(0.8F * CanvasWidth), (int)(0.8F * CanvasHeight));

            //Rectangle chart = new Rectangle();
            RectangleItems.Add(chart);

            //get the energy limit
            double lowE  = minAbsc;// Properties.Settings.Default.LOWERELIMT * 0.75;
            double highE = maxAbsc;

            //get the position converstion factors.
            double xconv = chart.Width / (highE - lowE);
            double xoff  = chart.Right - (xconv * highE);

            double yconv = chart.Height / (minOrd - maxOrd);
            double yoff  = chart.Bottom - (yconv * minOrd);


            //build a formatting string
            StringBuilder format = new StringBuilder("0");

            format.Append(ordTickMag >= 0 ? "" : ".");
            for (int j = 0; j < Math.Abs(ordTickMag); j++)
            {
                format.Append(0);
            }
            //loop through and add lables
            int    tickLength = 10;
            double ord = minOrd, absc = minAbsc;

            while (Math.Round(ord, (int)Math.Abs(ordTickMag)) <= maxOrd)
            {
                //draw the y-axis
                double y;// = (yconv * (ord) + yoff);
                if (Math.Abs(ord - minOrd) < 1e-6)
                {
                    y = chart.Bottom - chart.StrokeWeight / 2;
                }
                else if (Math.Abs(ord - maxOrd) < 1e-6)
                {
                    y = chart.Top + chart.StrokeWeight / 2;
                }
                else
                {
                    y = (yconv * (ord) + yoff);
                    LineItems.Add(new Line(chart.Left, y, chart.Right, y)
                    {
                        LineDashArray = { 2, 1 },
                    });
                }

                LineItems.Add(new Line(chart.Left - tickLength, y, chart.Left + tickLength, y));
                //create the label
                string    label     = (ord).ToString(format.ToString());
                ChartText labelText = new ChartText(label)
                {
                    //position the label
                    //X = chart.Left - 2 - 0.2*CanvasWidth,
                    X      = 0,
                    Y      = y + (ordTickRange * yconv) / 2,
                    Width  = chart.Left - tickLength - 2,
                    Height = Math.Abs(ordTickRange * yconv),
                    TextHorizontalAlignment = HorizontalAlignment.Right,
                    TextVerticalAlignment   = VerticalAlignment.Center
                };

                TextItems.Add(labelText);
                ord += ordTickRange;
            }
            while (Math.Round(absc, (int)Math.Abs(abscTickMag)) <= maxAbsc)
            {
                //draw the x-axis
                double x;// = (xconv * (absc) + xoff);
                if (Math.Abs(absc - minAbsc) < 1e-6)
                {
                    x = chart.Left + chart.StrokeWeight / 2;
                }
                else if (Math.Abs(absc - maxAbsc) < 1e-6)
                {
                    x = chart.Right - chart.StrokeWeight / 2;
                }
                else
                {
                    x = (xconv * (absc) + xoff);
                    LineItems.Add(new Line(x, chart.Bottom, x, chart.Top)
                    {
                        LineDashArray = { 2, 1 },
                    });
                }

                LineItems.Add(new Line(x, chart.Bottom + tickLength, x, chart.Bottom - tickLength));

                string    label     = (absc).ToString();
                ChartText labelText = new ChartText(label)
                {
                    Width  = abscTickRange * xconv,
                    Height = 0.2 * CanvasHeight - tickLength - 2 - seperation,
                    //position the label
                    X = x - (abscTickRange * xconv) / 2,
                    Y = chart.Bottom + tickLength + 2,
                    TextHorizontalAlignment = HorizontalAlignment.Center,
                    TextVerticalAlignment   = VerticalAlignment.Top
                };

                TextItems.Add(labelText);
                absc += abscTickRange;
            }

            //fill the an array of points that represents the curve
            double eJump = (highE - lowE) / numPoints;
            //CurvePoints = new Point[numPoints];
            double ene = lowE;

            for (int i = 0; i < numPoints; i++)
            {
                ene += eJump;
                double eff = data.GetEfficiency(ene);
                int    x   = Convert.ToInt32(ene * xconv + xoff);
                double y   = yoff + eff * yconv;
                if (y > chart.Bottom || double.IsNaN(y))
                {
                    y = chart.Bottom;
                }
                else if (y < chart.Top || double.IsInfinity(y))
                {
                    y = chart.Top;
                }

                points.Add(new Point(x, y));
            }
            this.CurvePoints = points;
            //make the graph thick
            //put the efficiency points on the chart
            for (int i = 0; i < EfficiencyMeasurements.Count; i++)
            {
                int x      = Convert.ToInt32(EfficiencyMeasurements[i].Energy * xconv + xoff);
                int y      = Convert.ToInt32(yoff + EfficiencyMeasurements[i].Efficiency * yconv);
                int ptSize = 2;
                RectangleItems.Add(new Rectangle(x - ptSize, y - ptSize, 2 * ptSize, 2 * ptSize));
                //add the error bars
                LineItems.Add(new Line(x, y - EfficiencyMeasurements[i].EfficiencyUncertainty * yconv,
                                       x, y + EfficiencyMeasurements[i].EfficiencyUncertainty * yconv));
            }
            WriteEfficiencyEquation();
        }