/// <summary>
        /// Reallocates the indicator line objects.
        /// </summary>
        private void AllocateIndicatorLines()
        {
            // Figure out how many lines we can show on the screen.
            double height = Allocation.Height;

            RegionBlockStyle style = Theme.RegionStyles[BackgroundRegionName];

            height -= style == null
                                ? 0
                                : style.Height;

            style   = Theme.RegionStyles[VisibleRegionName];
            height -= style == null
                                ? 0
                                : style.Height;

            visibleIndicatorLines = (int)Math.Floor(height / Theme.IndicatorPixelHeight);

            // Create a new indicator line which is then populated
            // with null values to reset the bar.
            indicatorLines = new IndicatorLine[visibleIndicatorLines];

            for (int index = 0;
                 index < visibleIndicatorLines;
                 index++)
            {
                indicatorLines[index] = new IndicatorLine();
            }

            // Assign the lines, since we may have changed.
            AssignIndicatorLines();
        }
Beispiel #2
0
 private void Awake()
 {
     Instance = this;
 }
        /// <summary>
        /// Called when the bar is exposed (drawn).
        /// </summary>
        /// <param name="exposeEvent">The drawing event..</param>
        /// <returns></returns>
        protected override bool OnExposeEvent(EventExpose exposeEvent)
        {
            // Figure out the area we are rendering into. We subtract one
            // from the width and height because of rounding causes one-pixel
            // borders off the bottom and right edges.
            Rectangle area      = exposeEvent.Region.Clipbox;
            var       cairoArea = new Cairo.Rectangle(
                area.X, area.Y, area.Width - 1, area.Height - 1);

            using (Context cairoContext = CairoHelper.Create(exposeEvent.Window))
            {
                // Create a render context.
                var renderContext = new RenderContext(cairoContext);
                renderContext.RenderRegion = cairoArea;

                // Paint the background of the entire indicator bar.
                BlockStyle backgroundStyle = Theme.RegionStyles[BackgroundRegionName]
                                             ?? new RegionBlockStyle();
                DrawingUtility.DrawLayout(
                    EditorView, renderContext, cairoArea, backgroundStyle);

                // Show the visible area, if we have one.
                BlockStyle visibleStyle = Theme.RegionStyles[VisibleRegionName];
                double     barX         = area.X + backgroundStyle.Left + 0.5;
                double     barWidth     = area.Width - backgroundStyle.Width - 1;
                double     barY         = area.Y + backgroundStyle.Top + 0.5;

                if (visibleStyle != null)
                {
                    // Figure out the area and adjust the bar variables with this style.
                    var visibleArea = new Cairo.Rectangle(
                        barX,
                        barY,
                        barWidth,
                        indicatorLinesUsed * Theme.IndicatorPixelHeight + visibleStyle.Height);

                    barX     += visibleStyle.Left;
                    barWidth -= visibleStyle.Width;
                    barY     += visibleStyle.Top;

                    // Draw the style's elements.
                    DrawingUtility.DrawLayout(
                        EditorView, renderContext, visibleArea, visibleStyle);
                }

                // Draw all the indicator lines on the display.
                cairoContext.LineWidth = EditorView.Theme.IndicatorPixelHeight;
                cairoContext.Antialias = Antialias.None;

                for (int index = 0;
                     index < indicatorLinesUsed;
                     index++)
                {
                    // Make sure the line has been processed and it visible.
                    IndicatorLine indicatorLine = indicatorLines[index];

                    if (!indicatorLine.NeedIndicators &&
                        indicatorLine.Visible)
                    {
                        indicatorLine.Draw(EditorView, cairoContext, barX, barY, barWidth);
                    }

                    // Shift the y-coordinate down.
                    barY += EditorView.Theme.IndicatorPixelHeight;
                }
            }

            // Return the render.
            return(base.OnExposeEvent(exposeEvent));
        }
        /// <summary>
        /// Called when the GUI is idle and we can finish updating.
        /// </summary>
        /// <returns>True if this idle should remain in effect.</returns>
        private bool OnIdle()
        {
            // Keep track of our start time since we want to limit how long
            // we are in this function. Using UtcNow is more efficient than
            // local time because it does no time zone processing.
            const int maximumProcessTime = 100;
            DateTime  start = DateTime.UtcNow;

            try
            {
                // Look for lines that need to be populated. We can do this since
                // we are on the GUI thread.
                bool startedAtBeginning = lastIndicatorLineUpdated == 0;

                for (int index = lastIndicatorLineUpdated;
                     index < indicatorLines.Length;
                     index++)
                {
                    // If we need data, then do something.
                    IndicatorLine indicatorLine = indicatorLines[index];

                    if (indicatorLine.NeedIndicators)
                    {
                        // We need to update this indicator.
                        indicatorLine.Update(EditorView, editorViewRenderer);
                    }

                    // Update the last indicator update.
                    lastIndicatorLineUpdated = index;

                    // Check to see if we exceeded our time.
                    TimeSpan elapsed = DateTime.UtcNow - start;

                    if (elapsed.TotalMilliseconds > maximumProcessTime)
                    {
                        return(true);
                    }
                }

                // If we didn't start at the beginning, then we start over to see if
                // there are more that need updating. Otherwise, we are done.
                if (startedAtBeginning)
                {
                    // We set the flag to indicate we aren't running an idle
                    // function and detach from GLib's idle processing. This is
                    // done to save CPU cycles when nothing changes.
                    using (new WriteLock(sync))
                    {
                        idleRunning = false;
                        return(false);
                    }
                }
                else
                {
                    lastIndicatorLineUpdated = 0;
                }
            }
            finally
            {
                // In all of these cases, we need to queue a redraw.
                QueueDraw();
            }

            return(true);
        }
        /// <summary>
        /// Goes through the buffer lines and assigns those lines to the
        /// indicator lines.
        /// </summary>
        private void AssignIndicatorLines()
        {
            // Go through all the lines and put them in a known and reset state.
            // Reset the lines we're using and clear out the lines we aren't.
            indicatorLinesUsed = 0;

            for (int indicatorLineIndex = 0;
                 indicatorLineIndex < visibleIndicatorLines;
                 indicatorLineIndex++)
            {
                IndicatorLine indicatorLine = indicatorLines[indicatorLineIndex];

                indicatorLine.Reset();
                indicatorLine.StartLineIndex = -1;
                indicatorLine.EndLineIndex   = -1;
            }

            // If we don't have any lines or if we have no height, then don't
            // do anything.
            if (visibleIndicatorLines == 0 ||
                editorViewRenderer == null ||
                editorViewRenderer.LineBuffer == null)
            {
                return;
            }

            // Check for lines in the buffer. If we have none, then we can't
            // do anything.
            int lineCount = EditorView.LineBuffer.LineCount;

            if (lineCount == 0)
            {
                return;
            }

            // Figure out roughly how many buffer lines we'll pack into a single
            // indicator line. This is a double since there will be a fractional
            // amount per line but it will fill out the height better.
            double bufferLinesPerIndicatorLine = Math.Max(
                1, (double)lineCount / visibleIndicatorLines);

            // Go through all the lines and allocate the ranges to each indicator
            // line.
            int    lastBufferLineIndex           = -1;
            double lastFractionalBufferLineIndex = 0.0;

            for (int indicatorLineIndex = 0;
                 indicatorLineIndex < visibleIndicatorLines;
                 indicatorLineIndex++)
            {
                // Get the indicator line for the current line.
                IndicatorLine indicatorLine = indicatorLines[indicatorLineIndex];

                indicatorLinesUsed++;

                // Figure out how many lines would be used at this point if
                // we were using doubles. We do this since 1.5 means that every
                // other line would have 2 instead of 1, but it would fill out
                // the visible bar better. Otherwise, doing it just through integer
                // math would cut the bar in half when it went from 1 to 2.
                lastFractionalBufferLineIndex += bufferLinesPerIndicatorLine;

                // Figure out the integer indexes for the start and end of this
                // indicator line.
                int startBufferLineIndex = lastBufferLineIndex + 1;
                int endBufferLineIndex   = Math.Min(
                    lineCount, (int)Math.Floor(lastFractionalBufferLineIndex)) - 1;

                lastBufferLineIndex = endBufferLineIndex;

                // Set up the indicator line for the given line indexes.
                indicatorLine.Visible        = true;
                indicatorLine.StartLineIndex = startBufferLineIndex;
                indicatorLine.EndLineIndex   = endBufferLineIndex;

                // If this range ends with the last line in the buffer, break out.
                if (endBufferLineIndex >= lineCount - 1)
                {
                    break;
                }
            }

            // Since we assigned the lines, we start updating the idle.
            StartBackgroundUpdate();
        }