Beispiel #1
0
        /// <summary>
        /// Paints control.
        /// </summary>
        /// <remarks>
        /// This paint function is non-standard in that it does not invoke base.DoPaint.
        /// Base paint would take care of children, BUT: we don't want that: we only paint visible results controls.
        /// In exchange, we must manually paint or one real child, the scroll bar.
        /// </remarks>
        public override void DoPaint(Graphics g)
        {
            // Content rectangle height and width
            int cw, ch;

            getContentSize(sbar.Parent == this, out cw, out ch);

            // Background
            using (Brush b = new SolidBrush(ZenParams.WindowColor))
            {
                g.FillRectangle(b, new Rectangle(0, 0, Width, Height));
            }
            // Border
            using (Pen p = new Pen(ZenParams.BorderColor))
            {
                g.DrawLine(p, 0, 0, Width, 0);
                g.DrawLine(p, Width - 1, 0, Width - 1, Height);
                g.DrawLine(p, Width - 1, Height - 1, 0, Height - 1);
                g.DrawLine(p, 0, Height - 1, 0, 0);
            }
            // Results
            g.ResetTransform();
            g.TranslateTransform(AbsLeft, AbsTop);
            g.Clip = new Region(new Rectangle(1, 1, cw, ch));
            lock (resCtrlsLO)
            {
                if (firstVisibleIdx != -1)
                {
                    int ix = firstVisibleIdx;
                    while (ix < resCtrls.Count)
                    {
                        OneResultControl orc = resCtrls[ix];
                        if (orc.RelTop >= ch + 1)
                        {
                            break;
                        }
                        g.ResetTransform();
                        g.TranslateTransform(orc.AbsLeft, orc.AbsTop);
                        orc.DoPaint(g);
                        ++ix;
                    }
                }
            }
            // Bottom overlay (results count, zoom, settings)
            g.ResetTransform();
            g.TranslateTransform(AbsLeft, AbsTop);
            g.Clip = new Region(new Rectangle(1, 1, cw, ch));
            doPaintBottomOverlay(g);
            // Scroll bar, if visible
            if (sbar.Parent == this)
            {
                g.ResetTransform();
                g.TranslateTransform(sbar.AbsLeft, sbar.AbsTop);
                g.Clip = new Region(new Rectangle(0, 0, sbar.Width, sbar.Height));
                sbar.DoPaint(g);
            }
            // Fade overaly above everything but scollbar
            Color colFade = getFadeColor();

            if (colFade.A != 0)
            {
                using (Brush b = new SolidBrush(colFade))
                {
                    g.ResetTransform();
                    g.TranslateTransform(AbsLeft, AbsTop);
                    Rectangle rect = new Rectangle(1, 1, cw, ch);
                    g.Clip = new Region(rect);
                    g.FillRectangle(b, rect);
                }
            }
        }
Beispiel #2
0
        private void reAnalyzeResultsDisplay()
        {
            // Content rectangle height and width
            int cw, ch;

            getContentSize(sbar.Parent == this, out cw, out ch);

            // Put scroll bar in its place, update its large change (which is always one full screen)
            // Call below will not change visibility, but update sbar position.
            setScrollbarVisibility(sbar.Parent == this);

            // No results being shown: done here
            if (resCtrls.Count == 0)
            {
                return;
            }

            // Pivot control: first one that's at least partially visible
            int pivotY  = 1;
            int pivotIX = -1;
            OneResultControl pivotCtrl = null;

            for (int i = 0; i != resCtrls.Count; ++i)
            {
                OneResultControl orc = resCtrls[i];
                // Results controls' absolute locations are within my full canvas
                // First visible one is the guy whose bottom is greater than 1
                if (orc.RelBottom > pivotY)
                {
                    pivotY    = orc.RelBottom;
                    pivotCtrl = orc;
                    pivotIX   = i;
                    break;
                }
            }
            // Recalculate each result control's layout, and height
            using (Bitmap bmp = new Bitmap(1, 1))
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    foreach (OneResultControl orc in resCtrls)
                    {
                        orc.Analyze(g, cw);
                    }
                }
            // Move pivot control back in place so bottom stays where it was
            // But: if pivot was first shown control at top, keep top in place
            int diff = pivotY - pivotCtrl.RelBottom;

            if (pivotIX == 0 && pivotCtrl.RelTop == 1)
            {
                diff = 0;
            }
            pivotCtrl.RelTop += diff;
            // Lay out remaining controls up and down
            for (int i = pivotIX + 1; i < resCtrls.Count; ++i)
            {
                resCtrls[i].RelTop = resCtrls[i - 1].RelBottom;
            }
            for (int i = pivotIX - 1; i >= 0; --i)
            {
                resCtrls[i].RelTop = resCtrls[i + 1].RelTop - resCtrls[i].Height;
            }
            // Edge case: very first control's top must not be greater than 1
            if (resCtrls[0].RelTop > 1)
            {
                diff = resCtrls[0].RelTop - 1;
                foreach (OneResultControl orc in resCtrls)
                {
                    orc.RelTop -= diff;
                }
            }
            // If there is space below very last control's bottom, but first control is above window edge
            // > Move down, but without detaching creating empty space at top
            int emptyAtBottom = Height - 1 - resCtrls[resCtrls.Count - 1].RelBottom;

            if (emptyAtBottom > 0)
            {
                int outsideAtTop = 1 - resCtrls[0].RelTop;
                diff = Math.Min(outsideAtTop, emptyAtBottom);
                if (diff > 0)
                {
                    foreach (OneResultControl orc in resCtrls)
                    {
                        orc.RelTop += diff;
                    }
                }
            }
            // Change our mind about scrollbar control?
            cw = showOrHideScrollbar();
            // Update first visible control's index
            updateFirstVisibleIdx();
        }
Beispiel #3
0
        /// <summary>
        /// See <see cref="SetResults"/>.
        /// </summary>
        private bool doSetResults(int lookupId,
                                  ICedictEntryProvider entryProvider,
                                  ReadOnlyCollection <CedictResult> results,
                                  SearchScript script)
        {
            lock (displayIdLO)
            {
                // If we're already too late, don't bother changing display.
                if (displayId > lookupId)
                {
                    return(false);
                }
                displayId = lookupId;
                // Empty result set - special handling
                if (results.Count == 0)
                {
                    lock (resCtrlsLO)
                    {
                        doDisposeResultControls();
                        txtResCount = tprov.GetString("ResultsCountNone");
                        setScrollbarVisibility(false);
                    }
                    // Render
                    doFade(false);
                    MakeMePaint(false, RenderMode.Invalidate);
                    return(true);
                }
            }

            // Decide if we first try with scrollbar visible or not
            // This is a very rough heuristics (10 results or more), but doesn't matter
            // Recalc costs much if there are many results, and the number covers that safely
            bool sbarVisible = results.Count > 10;

            // Content rectangle height and width
            int cw, ch;

            getContentSize(sbarVisible, out cw, out ch);

            // Create new result controls. At this point, not overwriting old ones!
            // This is the cycle that takes *long*.
            List <OneResultControl> newCtrls = new List <OneResultControl>(results.Count);
            int y = 0;

            using (Bitmap bmp = new Bitmap(1, 1))
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    bool canceled = false;
                    for (int rix = 0; rix != results.Count; ++rix)
                    {
                        CedictResult     cr  = results[rix];
                        OneResultControl orc = new OneResultControl(null, Scale, tprov,
                                                                    onLookupFromCtrl, onPaintFromCtrl, onGetEntry,
                                                                    entryProvider, cr, script, rix == results.Count - 1);
                        orc.Analyze(g, cw);
                        // Cannot use RelLocation b/c control has no parent yet
                        orc.AbsLocation = new Point(AbsLeft + 1, AbsTop + y + 1);
                        y += orc.Height;
                        newCtrls.Add(orc);
                        // At any point, if we realize lookup ID has changed, we stop
                        // This can happen if a later, quick lookup completes and shows results before us
                        // Checking integers is atomic, no locking
                        if (displayId > lookupId)
                        {
                            canceled = true; break;
                        }
                    }
                    if (canceled)
                    {
                        foreach (OneResultControl orc in newCtrls)
                        {
                            orc.Dispose();
                        }
                        return(false);
                    }
                }
            // OK, last chance to change our mind about showing results.
            // The rest is synchronized - but it's also fast
            lock (displayIdLO)
            {
                if (displayId > lookupId)
                {
                    return(false);
                }
                displayId = lookupId;
                // Rest must be invoked on GUI. Otherwise, as we're adding children,
                // Collections are modified that are also accessed by paint in a resize event handler etc.
                InvokeOnForm((MethodInvoker) delegate
                {
                    // Stop any scrolling that may be going on. Cannot scroll what's being replaced.
                    if (sbar.Parent == this)
                    {
                        sbar.StopAnyScrolling();
                    }
                    // Prevent any painting from worker threads - also accesses collection we're changing
                    lock (resCtrlsLO)
                    {
                        // Get rid of old result controls, remember/own new ones
                        doDisposeResultControls();
                        resCtrls = newCtrls;
                        foreach (OneResultControl orc in resCtrls)
                        {
                            AddChild(orc);
                        }
                        // Actually show or hide scrollbar as per original decision
                        setScrollbarVisibility(sbarVisible);
                        // Now, by the time we're here, size may have changed
                        // That is unlikely, but then we got to re-layout stuff
                        int cwNew, chNew;
                        getContentSize(sbarVisible, out cwNew, out chNew);
                        if (cwNew != cw || chNew != ch)
                        {
                            reAnalyzeResultsDisplay();
                        }
                        else
                        {
                            // Everything as big as it used to be...
                            // Change our mind about scrollbar?
                            cw = showOrHideScrollbar();
                        }
                    }
                    // Results count text
                    if (resCtrls.Count == 1)
                    {
                        txtResCount = tprov.GetString("ResultsCountOne");
                    }
                    else
                    {
                        txtResCount = tprov.GetString("ResultsCountN");
                        txtResCount = string.Format(txtResCount, resCtrls.Count);
                    }
                    // Update first visible control's index
                    updateFirstVisibleIdx();
                    // Render
                    doFade(false);
                    MakeMePaint(false, RenderMode.Invalidate);
                });
                // Done.
                return(true);
            }
        }
Beispiel #4
0
        /// <summary>
        /// See <see cref="SetResults"/>.
        /// </summary>
        private bool doSetResults(int lookupId,
            ICedictEntryProvider entryProvider,
            ReadOnlyCollection<CedictResult> results,
            SearchScript script)
        {
            lock (displayIdLO)
            {
                // If we're already too late, don't bother changing display.
                if (displayId > lookupId) return false;
                displayId = lookupId;
                // Empty result set - special handling
                if (results.Count == 0)
                {
                    lock (resCtrlsLO)
                    {
                        doDisposeResultControls();
                        txtResCount = tprov.GetString("ResultsCountNone");
                        setScrollbarVisibility(false);
                    }
                    // Render
                    doFade(false);
                    MakeMePaint(false, RenderMode.Invalidate);
                    return true;
                }
            }

            // Decide if we first try with scrollbar visible or not
            // This is a very rough heuristics (10 results or more), but doesn't matter
            // Recalc costs much if there are many results, and the number covers that safely
            bool sbarVisible = results.Count > 10;

            // Content rectangle height and width
            int cw, ch;
            getContentSize(sbarVisible, out cw, out ch);

            // Create new result controls. At this point, not overwriting old ones!
            // This is the cycle that takes *long*.
            List<OneResultControl> newCtrls = new List<OneResultControl>(results.Count);
            int y = 0;
            using (Bitmap bmp = new Bitmap(1, 1))
            using (Graphics g = Graphics.FromImage(bmp))
            {
                bool canceled = false;
                for (int rix = 0; rix != results.Count; ++rix)
                {
                    CedictResult cr = results[rix];
                    OneResultControl orc = new OneResultControl(null, Scale, tprov,
                        onLookupFromCtrl, onPaintFromCtrl, onGetEntry,
                        entryProvider, cr, script, rix == results.Count - 1);
                    orc.Analyze(g, cw);
                    // Cannot use RelLocation b/c control has no parent yet
                    orc.AbsLocation = new Point(AbsLeft + 1, AbsTop + y + 1);
                    y += orc.Height;
                    newCtrls.Add(orc);
                    // At any point, if we realize lookup ID has changed, we stop
                    // This can happen if a later, quick lookup completes and shows results before us
                    // Checking integers is atomic, no locking
                    if (displayId > lookupId) { canceled = true; break; }
                }
                if (canceled)
                {
                    foreach (OneResultControl orc in newCtrls) orc.Dispose();
                    return false;
                }
            }
            // OK, last chance to change our mind about showing results.
            // The rest is synchronized - but it's also fast
            lock (displayIdLO)
            {
                if (displayId > lookupId) return false;
                displayId = lookupId;
                // Rest must be invoked on GUI. Otherwise, as we're adding children,
                // Collections are modified that are also accessed by paint in a resize event handler etc.
                InvokeOnForm((MethodInvoker)delegate
                {
                    // Stop any scrolling that may be going on. Cannot scroll what's being replaced.
                    if (sbar.Parent == this) sbar.StopAnyScrolling();
                    // Prevent any painting from worker threads - also accesses collection we're changing
                    lock (resCtrlsLO)
                    {
                        // Get rid of old result controls, remember/own new ones
                        doDisposeResultControls();
                        resCtrls = newCtrls;
                        foreach (OneResultControl orc in resCtrls) AddChild(orc);
                        // Actually show or hide scrollbar as per original decision
                        setScrollbarVisibility(sbarVisible);
                        // Now, by the time we're here, size may have changed
                        // That is unlikely, but then we got to re-layout stuff
                        int cwNew, chNew;
                        getContentSize(sbarVisible, out cwNew, out chNew);
                        if (cwNew != cw || chNew != ch) reAnalyzeResultsDisplay();
                        else
                        {
                            // Everything as big as it used to be...
                            // Change our mind about scrollbar?
                            cw = showOrHideScrollbar();
                        }
                    }
                    // Results count text
                    if (resCtrls.Count == 1) txtResCount = tprov.GetString("ResultsCountOne");
                    else
                    {
                        txtResCount = tprov.GetString("ResultsCountN");
                        txtResCount = string.Format(txtResCount, resCtrls.Count);
                    }
                    // Update first visible control's index
                    updateFirstVisibleIdx();
                    // Render
                    doFade(false);
                    MakeMePaint(false, RenderMode.Invalidate);
                });
                // Done.
                return true;
            }
        }