265 lines
7.4 KiB
C#
265 lines
7.4 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
using JD.Kernel.Structs;
|
|
using JD.Sequencers.Controls;
|
|
|
|
namespace JD.Sequencers.Times
|
|
{
|
|
/// <summary>
|
|
/// The cursor that represents the "current time".
|
|
/// </summary>
|
|
public class TimeCursor : Guide
|
|
{
|
|
#region Inner Types
|
|
|
|
private class TimeScrollButton : Controls.Button
|
|
{
|
|
#region Variables
|
|
|
|
private readonly ScrollButton m_type;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public TimeScrollButton(ScrollButton type)
|
|
{
|
|
m_type = type;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public ScrollButton Type
|
|
{
|
|
get { return m_type; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
protected override void OnPaintSelf(PaintEventArgs e)
|
|
{
|
|
base.OnPaintSelf(e);
|
|
|
|
if (Bounds.Width > 0 || Bounds.Height > 0)
|
|
{
|
|
ControlPaint.DrawScrollButton(e.Graphics, Bounds, Type, ButtonState.Flat);
|
|
|
|
if (IsPressed)
|
|
{
|
|
using (Brush b = new SolidBrush(System.Drawing.Color.FromArgb(128, System.Drawing.Color.Lavender)))
|
|
{
|
|
e.Graphics.FillRectangle(b, Bounds);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constants
|
|
|
|
internal const int TotalWidth = 60;
|
|
private const int ButtonWidth = 12;
|
|
private const int DraggingPartWidth = TotalWidth - 2 * ButtonWidth;
|
|
|
|
#endregion
|
|
|
|
#region Variables
|
|
|
|
private readonly TimeScrollButton m_leftButton = new TimeScrollButton(ScrollButton.Left);
|
|
private readonly TimeScrollButton m_rightButton = new TimeScrollButton(ScrollButton.Right);
|
|
|
|
private bool m_isDragging;
|
|
private bool m_showIntervalSubdivisionInText;
|
|
private int m_adjustTextPositionY;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public TimeCursor(Timeline timeline)
|
|
: base(timeline)
|
|
{
|
|
Width = DraggingPartWidth;
|
|
Selectable = true;
|
|
|
|
Controls.Add(m_leftButton);
|
|
Controls.Add(m_rightButton);
|
|
|
|
m_leftButton.Click += button_Click;
|
|
m_rightButton.Click += button_Click;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// The amount of time units to add/substract when clicking on the arrows.
|
|
/// </summary>
|
|
private float Step
|
|
{
|
|
get { return Timeline.MinorInterval; }
|
|
}
|
|
|
|
public Rectangle BoundsWithButtons
|
|
{
|
|
get { return new Rectangle(m_leftButton.Bounds.X, m_leftButton.Bounds.Y, TotalWidth, Height); }
|
|
}
|
|
|
|
public int AdjustTextPositionY
|
|
{
|
|
get { return m_adjustTextPositionY; }
|
|
set
|
|
{
|
|
m_adjustTextPositionY = value;
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
public bool ShowIntervalSubdivisionInText
|
|
{
|
|
get { return m_showIntervalSubdivisionInText; }
|
|
set { m_showIntervalSubdivisionInText = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
#region Painting
|
|
|
|
protected override void OnPaintSelf(PaintEventArgs e)
|
|
{
|
|
UpdateBounds();
|
|
|
|
base.OnPaintSelf(e);
|
|
|
|
System.Drawing.Color baseColor = m_isDragging ? System.Drawing.Color.FromArgb(160, 230, 230, 230) : System.Drawing.Color.FromArgb(160, 50, 50, 50);
|
|
|
|
using (Brush b = new LinearGradientBrush(Bounds, Modify(baseColor, 30), System.Drawing.Color.FromArgb(baseColor.A - 80, Modify(baseColor, -30)), LinearGradientMode.Vertical))
|
|
{
|
|
e.Graphics.FillRectangle(b, Bounds);
|
|
}
|
|
|
|
Text = GetText();
|
|
|
|
DrawText(e.Graphics, Text, (int)System.Math.Floor(Location.X + (Width / 2.0)));
|
|
e.Graphics.DrawRectangle(Pens.Gray, Bounds);
|
|
}
|
|
|
|
public static System.Drawing.Color Modify(System.Drawing.Color source, int delta)
|
|
{
|
|
var colorRange = new Range<int>(0, 255);
|
|
Func<int, int> modifyChannel = x => colorRange.Clamp(x + delta);
|
|
return System.Drawing.Color.FromArgb(source.A, modifyChannel(source.R), modifyChannel(source.G), modifyChannel(source.B));
|
|
}
|
|
|
|
private string GetText()
|
|
{
|
|
return Timeline.TimeToText(Time, Timeline.MinorInterval, m_showIntervalSubdivisionInText);
|
|
}
|
|
|
|
private void DrawText(Graphics g, string text, int xPos)
|
|
{
|
|
SizeF size = g.MeasureString(text, Timeline.Font);
|
|
int x = (int)System.Math.Floor(xPos - (size.Width / 2.0));
|
|
int y = (int)System.Math.Floor((Location.Y + Height / 2.0) - (size.Height / 2.0));
|
|
|
|
g.DrawString(text, Timeline.Font, m_isDragging ? Brushes.Black : Brushes.DeepSkyBlue, new Point(x, y + m_adjustTextPositionY));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Bounds
|
|
|
|
protected override void OnTimeChanged(EventArgs e)
|
|
{
|
|
base.OnTimeChanged(e);
|
|
Invalidate();
|
|
}
|
|
|
|
protected override void OnBoundsChanged(EventArgs e)
|
|
{
|
|
base.OnBoundsChanged(e);
|
|
UpdateBounds();
|
|
}
|
|
|
|
private void UpdateBounds()
|
|
{
|
|
m_leftButton.Bounds = new Rectangle(Bounds.X - ButtonWidth, Bounds.Y, ButtonWidth, Height);
|
|
m_rightButton.Bounds = new Rectangle(Bounds.Right, Bounds.Y, ButtonWidth, Height);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Interaction
|
|
|
|
public virtual void GotoPreviousFrame()
|
|
{
|
|
int mul = (int)System.Math.Round(Time / Step) - 1;
|
|
Time = mul * Step;
|
|
}
|
|
|
|
public virtual void GotoNextFrame()
|
|
{
|
|
int mul = (int)System.Math.Round(Time / Step) + 1;
|
|
Time = mul * Step;
|
|
}
|
|
|
|
protected internal override void OnMouseDown(MouseEventArgs e)
|
|
{
|
|
if (IsMoveAllowed)
|
|
{
|
|
m_isDragging = true;
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
protected internal override void OnMouseUp(MouseEventArgs e)
|
|
{
|
|
if (m_isDragging)
|
|
{
|
|
m_isDragging = false;
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void button_Click(object sender, EventArgs e)
|
|
{
|
|
TimeScrollButton button = (TimeScrollButton)sender;
|
|
|
|
switch (button.Type)
|
|
{
|
|
case ScrollButton.Left:
|
|
GotoPreviousFrame();
|
|
break;
|
|
|
|
case ScrollButton.Right:
|
|
GotoNextFrame();
|
|
break;
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
// Recalculate the guide's position now
|
|
Location = new Point(Timeline.TimeToPixel(Time) - Width / 2, Timeline.Location.Y + Timeline.BorderWidth);
|
|
|
|
Cursor.Position = RootControl.PointToScreen(new Point(button.Bounds.X + button.Bounds.Width / 2,
|
|
button.Bounds.Y + button.Bounds.Height / 2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
}
|