rewrite SliderWidget to be simpler and have much less fail

This commit is contained in:
Chris Forbes
2011-07-17 15:07:08 +12:00
parent fe6a99c993
commit 0efe82018a
6 changed files with 67 additions and 154 deletions

View File

@@ -17,160 +17,78 @@ namespace OpenRA.Widgets
public class SliderWidget : Widget public class SliderWidget : Widget
{ {
public Func<bool> IsDisabled = () => false; public Func<bool> IsDisabled = () => false;
public event Action<float> OnChange; public event Action<float> OnChange = _ => {};
public Func<float> GetOffset;
public int Ticks = 0; public int Ticks = 0;
public int TrackHeight = 5; public int TrackHeight = 5;
// TODO: Changing this breaks the semantics of Get/SetOffset
// This is bogus
public float2 Range = new float2(0f, 1f); public float2 Range = new float2(0f, 1f);
public float Value = 0;
float Offset = 0;
int2 lastMouseLocation;
protected bool isMoving = false; protected bool isMoving = false;
public SliderWidget() public SliderWidget() : base() {}
: base()
{
GetOffset = () =>
{
var Big = Math.Max(Range.X, Range.Y);
var Little = Math.Min(Range.X, Range.Y);
var Spread = Big - Little;
return Spread * Offset + Little;
};
OnChange = x => Offset = x.Clamp(0f, 1f);
}
public SliderWidget(SliderWidget other) public SliderWidget(SliderWidget other)
: base(other) : base(other)
{ {
OnChange = other.OnChange; OnChange = other.OnChange;
GetOffset = other.GetOffset;
Ticks = other.Ticks; Ticks = other.Ticks;
Range = other.Range; Range = other.Range;
Offset = GetOffset();
TrackHeight = other.TrackHeight; TrackHeight = other.TrackHeight;
lastMouseLocation = other.lastMouseLocation;
isMoving = other.isMoving; isMoving = other.isMoving;
} }
public void SetOffset(float newOffset) void UpdateValue(float newValue)
{ {
var Big = Math.Max(Range.X, Range.Y); Value = newValue.Clamp(Range.X, Range.Y);
var Little = Math.Min(Range.X, Range.Y); OnChange(Value);
var Spread = Big - Little;
Offset = ((newOffset - Little) / Spread).Clamp(0f, 1f);
} }
public override bool HandleMouseInput(MouseInput mi) public override bool HandleMouseInput(MouseInput mi)
{ {
if (mi.Button != MouseButton.Left) if (mi.Button != MouseButton.Left) return false;
return false; if (IsDisabled()) return false;
if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) return false;
if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) if (!Focused) return false;
return false;
if (!Focused) switch( mi.Event )
return false;
switch (mi.Event)
{ {
case MouseInputEvent.Up: case MouseInputEvent.Up:
{ isMoving = false;
if (Focused) LoseFocus(mi);
{ break;
isMoving = false;
base.LoseFocus(mi);
}
}
break;
case MouseInputEvent.Down: case MouseInputEvent.Down:
{ isMoving = true;
if (thumbRect.Contains(mi.Location)) /* todo: handle snapping to ticks properly again */
{ /* todo: handle nudge via clicking outside the thumb */
isMoving = true; UpdateValue(ValueFromPx(mi.Location.X - RenderBounds.Left));
lastMouseLocation = mi.Location; break;
}
else if (Ticks != 0)
{
var pos = Offset;
// Offset slightly the direction we want to move so we don't get stuck on a tick case MouseInputEvent.Move:
var delta = 0.001; if (isMoving)
var targetTick = (float)((mi.Location.X > thumbRect.Right) ? Math.Ceiling((pos + delta) * (Ticks - 1)) UpdateValue(ValueFromPx(mi.Location.X - RenderBounds.Left));
: Math.Floor((pos - delta) * (Ticks - 1))); break;
OnChange(targetTick / (Ticks - 1));
if (thumbRect.Contains(mi.Location))
{
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 != Offset)
{
OnChange(newOffset);
if (thumbRect.Contains(mi.Location))
{
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); return ThumbRect.Contains(mi.Location);
} }
float OffsetBy(float amount) float ValueFromPx(int x) { return Range.X + (Range.Y - Range.X) * (1f * x / RenderBounds.Width); }
{ int PxFromValue(float x) { return (int)(RenderBounds.Width * (x - Range.X) / (Range.Y - Range.X)); }
var centerPos = Offset + amount;
if (centerPos < 0) centerPos = 0;
if (centerPos > 1) centerPos = 1;
return centerPos;
}
public override Widget Clone() { return new SliderWidget(this); } public override Widget Clone() { return new SliderWidget(this); }
protected Rectangle thumbRect Rectangle ThumbRect
{ {
get get
{ {
var width = RenderBounds.Height; var thumbPos = PxFromValue(Value);
var height = RenderBounds.Height; var rb = RenderBounds;
var origin = (int)((RenderBounds.X + width / 2) + Offset * (RenderBounds.Width - width) - width / 2f); var width = rb.Height;
return new Rectangle(origin, RenderBounds.Y, width, height); var height = rb.Height;
var origin = (int)(rb.X + thumbPos - width/2f);
return new Rectangle(origin, rb.Y, width, height);
} }
} }
@@ -179,16 +97,17 @@ namespace OpenRA.Widgets
if (!IsVisible()) if (!IsVisible())
return; return;
var tr = thumbRect; var tr = ThumbRect;
var trackWidth = RenderBounds.Width - tr.Width; var rb = RenderBounds;
var trackOrigin = RenderBounds.X + tr.Width / 2; var trackWidth = rb.Width;
var trackRect = new Rectangle(trackOrigin - 1, RenderBounds.Y + (RenderBounds.Height - TrackHeight) / 2, trackWidth + 2, TrackHeight); var trackOrigin = rb.X;
var trackRect = new Rectangle(trackOrigin - 1, rb.Y + (rb.Height - TrackHeight) / 2, trackWidth + 2, TrackHeight);
// Tickmarks (hacked until we have real art) // Tickmarks (hacked until we have real art)
for (int i = 0; i < Ticks; i++) for (int i = 0; i < Ticks; i++)
{ {
var tickRect = new Rectangle(trackOrigin - 1 + (int)(i * trackWidth * 1f / (Ticks - 1)), var tickRect = new Rectangle(trackOrigin - 1 + (int)(i * trackWidth * 1f / (Ticks - 1)),
RenderBounds.Y + RenderBounds.Height / 2, 2, RenderBounds.Height / 2); rb.Y + rb.Height / 2, 2, rb.Height / 2);
WidgetUtils.DrawPanel("slider-tick", tickRect); WidgetUtils.DrawPanel("slider-tick", tickRect);
} }

View File

@@ -33,9 +33,9 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
Action sliderChanged = () => Action sliderChanged = () =>
{ {
ramp = new ColorRamp((byte)(255*hueSlider.GetOffset()), ramp = new ColorRamp((byte)(255*hueSlider.Value),
(byte)(255*satSlider.GetOffset()), (byte)(255*satSlider.Value),
(byte)(255*lumSlider.GetOffset()), (byte)(255*lumSlider.Value),
10); 10);
onChange(ramp); onChange(ramp);
}; };
@@ -46,9 +46,9 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
Action updateSliders = () => Action updateSliders = () =>
{ {
hueSlider.SetOffset(ramp.H / 255f); hueSlider.Value = ramp.H / 255f;
satSlider.SetOffset(ramp.S / 255f); satSlider.Value = ramp.S / 255f;
lumSlider.SetOffset(ramp.L / 255f); lumSlider.Value = ramp.L / 255f;
}; };
panel.GetWidget<ButtonWidget>("SAVE_BUTTON").OnClick = () => onSelect(ramp); panel.GetWidget<ButtonWidget>("SAVE_BUTTON").OnClick = () => onSelect(ramp);

View File

@@ -104,9 +104,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
panel.GetWidget<LabelWidget>("TITLE_LABEL").GetText = () => (currentSong == null) ? "" : currentSong.Title; panel.GetWidget<LabelWidget>("TITLE_LABEL").GetText = () => (currentSong == null) ? "" : currentSong.Title;
var musicSlider = panel.GetWidget<SliderWidget>("MUSIC_SLIDER"); var musicSlider = panel.GetWidget<SliderWidget>("MUSIC_SLIDER");
musicSlider.OnChange += x => { Sound.MusicVolume = x; }; musicSlider.OnChange += x => Sound.MusicVolume = x;
musicSlider.GetOffset = () => { return Sound.MusicVolume; }; musicSlider.Value = Sound.MusicVolume;
musicSlider.SetOffset(Sound.MusicVolume);
} }
void BuildMusicTable(Widget list) void BuildMusicTable(Widget list)

View File

@@ -96,13 +96,11 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
// Audio // Audio
var soundSlider = generalPane.GetWidget<SliderWidget>("SOUND_SLIDER"); var soundSlider = generalPane.GetWidget<SliderWidget>("SOUND_SLIDER");
soundSlider.OnChange += x => { soundSettings.SoundVolume = x; Sound.SoundVolume = x;}; soundSlider.OnChange += x => { soundSettings.SoundVolume = x; Sound.SoundVolume = x;};
soundSlider.GetOffset = () => { return soundSettings.SoundVolume; }; soundSlider.Value = soundSettings.SoundVolume;
soundSlider.SetOffset(soundSettings.SoundVolume);
var musicSlider = generalPane.GetWidget<SliderWidget>("MUSIC_SLIDER"); var musicSlider = generalPane.GetWidget<SliderWidget>("MUSIC_SLIDER");
musicSlider.OnChange += x => { soundSettings.MusicVolume = x; Sound.MusicVolume = x; }; musicSlider.OnChange += x => { soundSettings.MusicVolume = x; Sound.MusicVolume = x; };
musicSlider.GetOffset = () => { return soundSettings.MusicVolume; }; musicSlider.Value = soundSettings.MusicVolume;
musicSlider.SetOffset(soundSettings.MusicVolume);
var shellmapMusicCheckbox = generalPane.GetWidget<CheckboxWidget>("SHELLMAP_MUSIC"); var shellmapMusicCheckbox = generalPane.GetWidget<CheckboxWidget>("SHELLMAP_MUSIC");
shellmapMusicCheckbox.IsChecked = () => gameSettings.ShellmapMusic; shellmapMusicCheckbox.IsChecked = () => gameSettings.ShellmapMusic;
@@ -120,8 +118,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
inputPane.GetWidget<CheckboxWidget>("CLASSICORDERS_CHECKBOX").IsDisabled = () => true; inputPane.GetWidget<CheckboxWidget>("CLASSICORDERS_CHECKBOX").IsDisabled = () => true;
var scrollSlider = inputPane.GetWidget<SliderWidget>("SCROLLSPEED_SLIDER"); var scrollSlider = inputPane.GetWidget<SliderWidget>("SCROLLSPEED_SLIDER");
scrollSlider.Value = gameSettings.ViewportEdgeScrollStep;
scrollSlider.OnChange += x => gameSettings.ViewportEdgeScrollStep = x; scrollSlider.OnChange += x => gameSettings.ViewportEdgeScrollStep = x;
scrollSlider.SetOffset(gameSettings.ViewportEdgeScrollStep);
var edgescrollCheckbox = inputPane.GetWidget<CheckboxWidget>("EDGESCROLL_CHECKBOX"); var edgescrollCheckbox = inputPane.GetWidget<CheckboxWidget>("EDGESCROLL_CHECKBOX");
edgescrollCheckbox.IsChecked = () => gameSettings.ViewportEdgeScroll; edgescrollCheckbox.IsChecked = () => gameSettings.ViewportEdgeScroll;

View File

@@ -289,27 +289,27 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{ {
var colorChooser = Game.modData.WidgetLoader.LoadWidget( new WidgetArgs() { {"worldRenderer", worldRenderer} }, null, "COLOR_CHOOSER" ); var colorChooser = Game.modData.WidgetLoader.LoadWidget( new WidgetArgs() { {"worldRenderer", worldRenderer} }, null, "COLOR_CHOOSER" );
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER"); var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
hueSlider.SetOffset(orderManager.LocalClient.ColorRamp.H / 255f); hueSlider.Value = orderManager.LocalClient.ColorRamp.H / 255f;
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER"); var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
satSlider.SetOffset(orderManager.LocalClient.ColorRamp.S / 255f); satSlider.Value = orderManager.LocalClient.ColorRamp.S / 255f;
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER"); var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
lumSlider.SetOffset(orderManager.LocalClient.ColorRamp.L / 255f); lumSlider.Value = orderManager.LocalClient.ColorRamp.L / 255f;
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER"); var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
rangeSlider.SetOffset(orderManager.LocalClient.ColorRamp.R / 255f); rangeSlider.Value = orderManager.LocalClient.ColorRamp.R / 255f;
hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.Value, satSlider.Value, lumSlider.Value, rangeSlider.Value);
satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); satSlider.OnChange += _ => UpdateColorPreview(hueSlider.Value, satSlider.Value, lumSlider.Value, rangeSlider.Value);
lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.Value, satSlider.Value, lumSlider.Value, rangeSlider.Value);
rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.Value, satSlider.Value, lumSlider.Value, rangeSlider.Value);
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); UpdateColorPreview(hueSlider.Value, satSlider.Value, lumSlider.Value, rangeSlider.Value);
colorChooser.GetWidget<ButtonWidget>("BUTTON_OK").OnClick = () => colorChooser.GetWidget<ButtonWidget>("BUTTON_OK").OnClick = () =>
{ {
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); UpdateColorPreview(hueSlider.Value, satSlider.Value, lumSlider.Value, rangeSlider.Value);
UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); UpdatePlayerColor(hueSlider.Value, satSlider.Value, lumSlider.Value, rangeSlider.Value);
color.RemovePanel(); color.RemovePanel();
}; };

View File

@@ -51,9 +51,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
edgescrollCheckbox.OnClick = () => Game.Settings.Game.ViewportEdgeScroll ^= true; edgescrollCheckbox.OnClick = () => Game.Settings.Game.ViewportEdgeScroll ^= true;
var edgeScrollSlider = general.GetWidget<SliderWidget>("EDGE_SCROLL_AMOUNT"); var edgeScrollSlider = general.GetWidget<SliderWidget>("EDGE_SCROLL_AMOUNT");
edgeScrollSlider.SetOffset(Game.Settings.Game.ViewportEdgeScrollStep); edgeScrollSlider.Value = Game.Settings.Game.ViewportEdgeScrollStep;
edgeScrollSlider.OnChange += _ => { Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset(); }; edgeScrollSlider.OnChange += x => Game.Settings.Game.ViewportEdgeScrollStep = x;
Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset();
var inversescroll = general.GetWidget<CheckboxWidget>("INVERSE_SCROLL"); var inversescroll = general.GetWidget<CheckboxWidget>("INVERSE_SCROLL");
inversescroll.IsChecked = () => Game.Settings.Game.MouseScroll == MouseScrollType.Inverted; inversescroll.IsChecked = () => Game.Settings.Game.MouseScroll == MouseScrollType.Inverted;
@@ -68,13 +67,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var soundslider = audio.GetWidget<SliderWidget>("SOUND_VOLUME"); var soundslider = audio.GetWidget<SliderWidget>("SOUND_VOLUME");
soundslider.OnChange += x => Sound.SoundVolume = x; soundslider.OnChange += x => Sound.SoundVolume = x;
soundslider.GetOffset = () => Sound.SoundVolume; soundslider.Value = Sound.SoundVolume;
soundslider.SetOffset(Sound.SoundVolume);
var musicslider = audio.GetWidget<SliderWidget>("MUSIC_VOLUME"); var musicslider = audio.GetWidget<SliderWidget>("MUSIC_VOLUME");
musicslider.OnChange += x => Sound.MusicVolume = x; musicslider.OnChange += x => Sound.MusicVolume = x;
musicslider.GetOffset = () => Sound.MusicVolume; musicslider.Value = Sound.MusicVolume;
musicslider.SetOffset(Sound.MusicVolume);
// Display // Display
var display = bg.GetWidget("DISPLAY_PANE"); var display = bg.GetWidget("DISPLAY_PANE");