Пример #1
0
        private void picSlider_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(BackColor);

            // Any messages in case of any errors
            string errorMessage = null;

            if (Animation == null)
            {
                errorMessage = "No animation! Create or select animation to start editing.";
            }
            else if (Animation.DirectXAnimation.KeyFrames.Count == 0)
            {
                errorMessage = "No frames! Add some frames to start editing.";
            }

            if (!string.IsNullOrEmpty(errorMessage))
            {
                using (var b = new SolidBrush(Colors.DisabledText))
                    e.Graphics.DrawString(errorMessage, Font, b, ClientRectangle,
                                          new StringFormat {
                        Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center
                    });
                return;
            }

            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

            // Draw state change ranges
            foreach (var sch in Animation.WadAnimation.StateChanges)
            {
                foreach (var disp in sch.Dispatches)
                {
                    int realOutFrame = disp.OutFrame >= realFrameCount ? realFrameCount - 1 : disp.OutFrame;
                    e.Graphics.FillRectangle(_stateChangeBrush, new RectangleF(picSlider.Padding.Left + (disp.InFrame * frameStep),
                                                                               picSlider.Padding.Top,
                                                                               (realOutFrame - disp.InFrame) * frameStep,
                                                                               picSlider.ClientSize.Height / _stateChangeMarkerThicknessDivider - picSlider.Padding.Bottom - 2));
                }
            }

            int halfCursorWidth = (int)Math.Round(_cursorWidth / 2.0f);

            // Shift the cursor at start/stop positions to prevent clipping
            int addShift = -halfCursorWidth;

            if (Value == 0)
            {
                addShift += halfCursorWidth;
            }
            else if (Value == Maximum)
            {
                addShift += -halfCursorWidth;
            }

            // Draw selection and highlight in 2 passes
            for (int passes = 0; passes < 2; passes++)
            {
                int x     = passes == 0 ? Selection.X : _highlightStart;
                int y     = passes == 0 ? Selection.Y : _highlightEnd;
                int realX = ValueToX(x);
                int realY = ValueToX(y);
                int size  = realY - realX;

                if ((passes == 0 && !SelectionIsEmpty) || (passes == 1 && _highlightTimer.Enabled))
                {
                    int       width = size == 0 ? _cursorWidth : size + _cursorWidth;
                    Rectangle rect  = new Rectangle(realX + picSlider.Padding.Left - halfCursorWidth, picSlider.Padding.Top, width, picSlider.ClientSize.Height - picSlider.Padding.Bottom);;

                    if (size == 0)
                    {
                        if (y != Minimum && y == Maximum)
                        {
                            rect.X -= halfCursorWidth;
                        }
                        else if (x == Minimum)
                        {
                            rect.X += halfCursorWidth;
                        }
                    }
                    else
                    {
                        if (x == Minimum)
                        {
                            rect.X     += halfCursorWidth;
                            rect.Width -= halfCursorWidth;
                        }
                        if (y == Maximum)
                        {
                            rect.Width -= halfCursorWidth;
                        }
                    }

                    if (passes == 0)
                    {
                        e.Graphics.FillRectangle(_selectionBrush, rect);
                        e.Graphics.DrawRectangle(_selectionPen, rect);
                    }
                    else
                    {
                        using (SolidBrush currBrush = (SolidBrush)_highlightBrush.Clone())
                        {
                            currBrush.Color = Color.FromArgb((int)((float)currBrush.Color.A * _highlightCounter), currBrush.Color);
                            e.Graphics.FillRectangle(currBrush, rect);
                        }
                    }
                }
            }

            // Measure maximum label size
            SizeF maxLabelSize = TextRenderer.MeasureText(realFrameCount.ToString(), Font,
                                                          new Size(picSlider.Width - picSlider.Padding.Horizontal, picSlider.Height - picSlider.Padding.Vertical),
                                                          TextFormatFlags.WordBreak);

            // Precache animcommands so we don't iterate them every drawn frame
            var acList = new List <KeyValuePair <int, WadAnimCommand> >();

            foreach (var ac in Animation.WadAnimation.AnimCommands.Where(ac => ac.FrameBased))
            {
                acList.Add(new KeyValuePair <int, WadAnimCommand>(ac.Parameter1, ac));
            }


            // Precache some variables for speeding up renderer with ultra-long animations (5000+ frames)
            var step          = frameStep;
            var padding       = picSlider.Padding;
            var drawStepWidth = _keyFrameBorderPen.Width * 4;

            // Draw frame-specific animcommands, numericals and dividers
            for (int passes = 0; passes < 2; passes++)
            {
                for (int i = 0; i < realFrameCount; ++i)
                {
                    int  currX      = (int)MathC.Round(step * i) + padding.Left;
                    bool isKeyFrame = (i % (Animation.WadAnimation.FrameRate == 0 ? 1 : Animation.WadAnimation.FrameRate) == 0);
                    bool first      = i == 0;
                    bool last       = i >= realFrameCount - 1;

                    if (passes == 0)
                    {
                        int count = 0;

                        // Draw animcommands
                        if (acList.Count > 0)
                        {
                            foreach (var acPair in acList)
                            {
                                var       ac         = acPair.Value;
                                Rectangle currRect   = new Rectangle(currX - _animCommandMarkerRadius / 2, padding.Top - _animCommandMarkerRadius / 2 + (_animCommandMarkerRadius / 3 * count), _animCommandMarkerRadius, _animCommandMarkerRadius);
                                float     startAngle = !first ? (!last ? 0 : 90) : 0;
                                float     endAngle   = !first ? (!last ? 180 : 90) : 90;

                                if (ac.Parameter1 == i)
                                {
                                    using (SolidBrush currBrush = (SolidBrush)(ac.Type == WadAnimCommandType.PlaySound ? _animCommandSoundBrush : _animCommandFlipeffectBrush).Clone())
                                    {
                                        currBrush.Color = Color.FromArgb((int)((float)currBrush.Color.A / (1.0f + ((float)count / 3.0f))), currBrush.Color);
                                        e.Graphics.FillPie(currBrush, currRect, startAngle, endAngle);
                                        count++;
                                    }
                                }
                            }
                            acList.RemoveAll(ac => ac.Key == i); // Remove already drawn animcommands from list
                        }

                        // Determine if current line should be drawn.
                        bool drawCurrentLine = true;
                        if (step < drawStepWidth)
                        {
                            int period = (int)MathC.Round(drawStepWidth / step);
                            if (i % period != 0 && i != realFrameCount - 1)
                            {
                                drawCurrentLine = false;
                            }
                        }

                        if (drawCurrentLine)
                        {
                            // Draw frame lines
                            e.Graphics.SmoothingMode = SmoothingMode.Default;

                            var lineHeight = picSlider.Height / (isKeyFrame ? 2 : 3);
                            if (isKeyFrame)
                            {
                                e.Graphics.DrawLine(_keyFrameBorderPen, currX, padding.Top, currX, lineHeight);  // Draw keyframe
                            }
                            else
                            {
                                e.Graphics.DrawLine(_frameBorderPen, currX, padding.Top, currX, lineHeight);  // Draw ordinary frame
                            }
                            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                        }
                    }

                    // Draw cursor on 2nd pass's first occurence (only for real animations, not for single-frame ones)
                    if (i == 0 && passes == 1 && realFrameCount > 1)
                    {
                        e.Graphics.FillRectangle(_cursorBrush, new RectangleF(ValueToX(Value) + addShift + padding.Left, padding.Top, _cursorWidth, picSlider.ClientSize.Height - padding.Bottom - 2));
                    }

                    // Draw labels
                    bool drawCurrentLabel = true;
                    if ((passes == 0 && !isKeyFrame) || (passes != 0 && isKeyFrame))
                    {
                        // Determine if labels are overlapping and decide on drawing
                        if (step < maxLabelSize.Width * 1.25)
                        {
                            int period = (int)MathC.Round(maxLabelSize.Width * 1.25 / step);
                            if (i % period != 0)
                            {
                                drawCurrentLabel = false;
                            }
                        }

                        if (drawCurrentLabel)
                        {
                            // Align first and last numerical entries so they are not concealed by control border
                            StringAlignment align = StringAlignment.Center;
                            int             shift = 0;
                            if (first)
                            {
                                shift -= padding.Left;
                                align  = StringAlignment.Near;
                            }
                            else if (last)
                            {
                                shift += padding.Left;
                                align  = StringAlignment.Far;
                            }

                            // Finally draw it after all these tests
                            e.Graphics.DrawString(i.ToString(), Font, (isKeyFrame ? _lblKeyframeBrush : _lblFrameBrush), currX + shift, picSlider.Height,
                                                  new StringFormat {
                                Alignment = align, LineAlignment = StringAlignment.Far
                            });
                        }
                    }
                }
            }

            // Draw horizontal guide (only for real anims, for single-frame anims we wouldn't wanna show that
            if (realFrameCount > 1)
            {
                e.Graphics.SmoothingMode = SmoothingMode.Default;
                e.Graphics.DrawLine(_keyFrameBorderPen, padding.Left, padding.Top + 1, picSlider.ClientSize.Width - padding.Left, padding.Top + 1);
            }
        }