using System; using System.Drawing; namespace OpenRA.Widgets { public class SliderWidget : Widget { public event Action OnChange; public Func GetOffset; public float Offset = 0; public int Ticks = 0; public int TrackHeight = 5; int2 lastMouseLocation; bool isMoving = false; public SliderWidget () : base() { GetOffset = () => Offset; OnChange = x => Offset = x; } public SliderWidget(Widget other) : base(other) { OnChange = (other as SliderWidget).OnChange; GetOffset = (other as SliderWidget).GetOffset; Offset = (other as SliderWidget).Offset; Ticks = (other as SliderWidget).Ticks; TrackHeight = (other as SliderWidget).TrackHeight; lastMouseLocation = (other as SliderWidget).lastMouseLocation; isMoving = (other as SliderWidget).isMoving; } public override bool HandleInput(MouseInput mi) { if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) return false; if (!Focused) return false; switch (mi.Event) { case MouseInputEvent.Up: { if (Focused) { isMoving = false; base.LoseFocus(mi); } } break; case MouseInputEvent.Down: { if (thumbRect.Contains(mi.Location.ToPoint())) { isMoving = true; lastMouseLocation = mi.Location; } else if (Ticks != 0) { var pos = GetOffset(); // Offset slightly the direction we want to move so we don't get stuck on a tick var delta = 0.001; var targetTick = (float)((mi.Location.X > thumbRect.Right) ? Math.Ceiling((pos+delta)*(Ticks-1)) : Math.Floor((pos-delta)*(Ticks-1))); OnChange(targetTick/(Ticks-1)); if (thumbRect.Contains(mi.Location.ToPoint())) { isMoving = true; lastMouseLocation = mi.Location; } return true; } else // No ticks; move to the mouse position { var thumb = thumbRect; var center = thumb.X + thumb.Width/2; var newOffset = OffsetBy((mi.Location.X - center)*1f/(RenderBounds.Width-thumb.Width)); if (newOffset != GetOffset()) { OnChange(newOffset); if (thumbRect.Contains(mi.Location.ToPoint())) { isMoving = true; lastMouseLocation = mi.Location; } return true; } } } break; case MouseInputEvent.Move: { if ((mi.Location.X != lastMouseLocation.X) && isMoving) { var newOffset = OffsetBy((mi.Location.X - lastMouseLocation.X)*1f/(RenderBounds.Width-thumbRect.Width)); if (newOffset != Offset) { lastMouseLocation = mi.Location; OnChange(newOffset); } } } break; } return thumbRect.Contains(mi.Location.X,mi.Location.Y); } float OffsetBy(float amount) { var centerPos = GetOffset() + amount; if (centerPos < 0) centerPos = 0; if (centerPos > 1) centerPos = 1; return centerPos; } public override Widget Clone() { return new SliderWidget(this); } Rectangle thumbRect { get { var width = RenderBounds.Height; var height = RenderBounds.Height; var origin = (int)((RenderBounds.X + width/2) + GetOffset()*(RenderBounds.Width - width) - width/2f); return new Rectangle(origin, RenderBounds.Y, width, height); } } public override void DrawInner(World world) { if (!IsVisible()) return; var trackWidth = RenderBounds.Width - thumbRect.Width; var trackOrigin = RenderBounds.X + thumbRect.Width/2; var trackRect = new Rectangle(trackOrigin-1, RenderBounds.Y + (RenderBounds.Height - TrackHeight)/2, trackWidth+2, TrackHeight); // Tickmarks (hacked until we have real art) for (int i = 0; i < Ticks; i++) { var tickRect = new Rectangle(trackOrigin -1 + (int)(i*trackWidth*1f/(Ticks-1)), RenderBounds.Y + RenderBounds.Height/2, 2, RenderBounds.Height/2); WidgetUtils.DrawPanel("dialog2", tickRect); } // Track WidgetUtils.DrawPanel("dialog3", trackRect); // Thumb WidgetUtils.DrawPanel("dialog2", thumbRect); } } }