Skip to content

Commit

Permalink
Merge branch 'master' into log-overlay-defaults-off
Browse files Browse the repository at this point in the history
  • Loading branch information
peppy authored Nov 20, 2017
2 parents acebd43 + 3b1460f commit 07aa057
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 245 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public abstract class FocusedOverlayContainer : OverlayContainer

protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (HasFocus && State == Visibility.Visible)
if (HasFocus && State == Visibility.Visible && !args.Repeat)
{
switch (args.Key)
{
Expand Down
26 changes: 14 additions & 12 deletions osu.Framework/Graphics/Sprites/SpriteText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,7 @@ private void load(FontStore store)

spaceWidth = CreateCharacterDrawable('.')?.DrawWidth * 2 ?? default_text_size;

if (!string.IsNullOrEmpty(text))
{
//this is used to prepare the initial string (useful for intial preloading).
foreach (char c in text)
if (!char.IsWhiteSpace(c)) CreateCharacterDrawable(c);
}
validateLayout();
}

private Bindable<string> current;
Expand Down Expand Up @@ -222,7 +217,11 @@ public string Text
protected override void Update()
{
base.Update();
validateLayout();
}

private void validateLayout()
{
if (!layout.IsValid)
{
computeLayout();
Expand All @@ -244,12 +243,6 @@ public override bool Invalidate(Invalidation invalidation = Invalidation.All, Dr

private void computeLayout()
{
if (FixedWidth && !constantWidth.HasValue)
constantWidth = CreateCharacterDrawable('D').DrawWidth;

//keep sprites which haven't changed since last layout.
List<Drawable> keepDrawables = new List<Drawable>();

bool allowKeepingExistingDrawables = true;

//adjust shadow alpha based on highest component intensity to avoid muddy display of darker text.
Expand All @@ -264,8 +257,14 @@ private void computeLayout()
lastShadowAlpha = shadowAlpha;
lastFont = font;

//keep sprites which haven't changed since last layout.
List<Drawable> keepDrawables = new List<Drawable>();

if (allowKeepingExistingDrawables)
{
if (lastText == text)
return;

int length = Math.Min(lastText?.Length ?? 0, text.Length);
keepDrawables.AddRange(Children.TakeWhile((n, i) => i < length && lastText[i] == text[i]));
RemoveRange(keepDrawables); //doesn't dispose
Expand All @@ -276,6 +275,9 @@ private void computeLayout()
if (text.Length == 0)
return;

if (FixedWidth && !constantWidth.HasValue)
constantWidth = CreateCharacterDrawable('D').DrawWidth;

foreach (var k in keepDrawables)
Add(k);

Expand Down
4 changes: 2 additions & 2 deletions osu.Framework/Graphics/UserInterface/TextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ public class TextBox : TabbableContainer, IHasCurrentValue<string>

public TextBox()
{
Masking = true;
CornerRadius = 3;
// TextBoxes currently require their own top-level PlatformInputManager, as InputManagers
// will not propagate events through other InputManagers.
// Once this restriction has been addressed, we can utilise a single instance of PlatformInputManager
// at the Game level, and TextBoxes need only implement IKeyBindingHandler<PlatformAction>.
Child = new PlatformInputManager
{
Masking = true,
CornerRadius = 3,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
Expand Down
162 changes: 78 additions & 84 deletions osu.Framework/Input/InputManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,15 +205,15 @@ protected bool ChangeFocus(Drawable potentialFocusTarget, InputState state)

protected override void Update()
{
var pendingStates = createDistinctInputStates(GetPendingStates()).ToArray();

unfocusIfNoLongerValid();
List<InputState> distinctStates = createDistinctStates(GetPendingStates()).ToList();

//we need to make sure the code in the foreach below is run at least once even if we have no new pending states.
if (pendingStates.Length == 0)
pendingStates = new[] { new InputState() };
if (distinctStates.Count == 0)
distinctStates.Add(new InputState());

foreach (InputState s in pendingStates)
unfocusIfNoLongerValid();

foreach (InputState s in distinctStates)
HandleNewState(s);

if (CurrentState.Mouse != null)
Expand Down Expand Up @@ -277,83 +277,6 @@ protected virtual void HandleNewState(InputState state)
updateKeyboardEvents(CurrentState);
}

/// <summary>
/// In order to provide a reliable event system to drawables, we want to ensure that we reprocess input queues (via the
/// main loop in<see cref="updateInputQueues(InputState)"/> after each and every button or key change. This allows
/// correct behaviour in a case where the input queues change based on triggered by a button or key.
/// </summary>
/// <param name="states">A list of <see cref="InputState"/>s</param>
/// <returns>Processed states such that at most one button change occurs between any two consecutive states.</returns>
private IEnumerable<InputState> createDistinctInputStates(List<InputState> states)
{
InputState last = CurrentState;

foreach (var i in states)
{
//first we want to create a copy of ourselves without any button changes
//we do this by updating our buttons to the state of the last frame.
var iWithoutButtons = i.Clone();

var iHasMouse = iWithoutButtons.Mouse != null;
var iHasKeyboard = iWithoutButtons.Keyboard != null;

if (iHasMouse)
for (MouseButton b = 0; b < MouseButton.LastButton; b++)
iWithoutButtons.Mouse.SetPressed(b, last.Mouse?.IsPressed(b) ?? false);

if (iHasKeyboard)
iWithoutButtons.Keyboard.Keys = last.Keyboard?.Keys ?? new Key[] { };

//we start by adding this state to the processed list...
yield return iWithoutButtons;
last = iWithoutButtons;

//and then iterate over each button/key change, adding intermediate states along the way.
if (iHasMouse)
{
for (MouseButton b = 0; b < MouseButton.LastButton; b++)
{
if (i.Mouse.IsPressed(b) != (last.Mouse?.IsPressed(b) ?? false))
{
var intermediateState = last.Clone();
if (intermediateState.Mouse == null) intermediateState.Mouse = new MouseState();

//add our single local change
intermediateState.Mouse.SetPressed(b, i.Mouse.IsPressed(b));

last = intermediateState;
yield return intermediateState;
}
}
}

if (iHasKeyboard)
{
foreach (var releasedKey in last.Keyboard?.Keys.Except(i.Keyboard.Keys) ?? new Key[] { })
{
var intermediateState = last.Clone();
if (intermediateState.Keyboard == null) intermediateState.Keyboard = new KeyboardState();

intermediateState.Keyboard.Keys = intermediateState.Keyboard.Keys.Where(d => d != releasedKey);

last = intermediateState;
yield return intermediateState;
}

foreach (var pressedKey in i.Keyboard.Keys.Except(last.Keyboard?.Keys ?? new Key[] { }))
{
var intermediateState = last.Clone();
if (intermediateState.Keyboard == null) intermediateState.Keyboard = new KeyboardState();

intermediateState.Keyboard.Keys = intermediateState.Keyboard.Keys.Union(new[] { pressedKey });

last = intermediateState;
yield return intermediateState;
}
}
}
}

protected virtual List<InputState> GetPendingStates()
{
var pendingStates = new List<InputState>();
Expand Down Expand Up @@ -518,7 +441,7 @@ private void updateMouseEvents(InputState state)
}
}

if (mouse.WheelDelta != 0)
if (mouse.WheelDelta != 0 && Host.Window.CursorInWindow)
handleWheel(state);

if (mouse.HasAnyButtonPressed)
Expand Down Expand Up @@ -823,6 +746,77 @@ private bool unfocusIfNoLongerValid()
}

private void focusTopMostRequestingDrawable() => ChangeFocus(inputQueue.FirstOrDefault(target => target.RequestsFocus));

/// <summary>
/// In order to provide a reliable event system to drawables, we want to ensure that we reprocess input queues (via the
/// main loop in <see cref="InputManager"/> after each and every button or key change. This allows
/// correct behaviour in a case where the input queues change based on triggered by a button or key.
/// </summary>
/// <param name="newStates">One ore more states which are to be converted to distinct states.</param>
/// <returns>Processed states such that at most one attribute change occurs between any two consecutive states.</returns>
private IEnumerable<InputState> createDistinctStates(IEnumerable<InputState> newStates)
{
IKeyboardState lastKeyboard = CurrentState.Keyboard;
IMouseState lastMouse = CurrentState.Mouse;

foreach (var state in newStates)
{
if (state.Mouse == null && state.Keyboard == null)
{
// we still want to return at least one state change.
yield return state;
}

if (state.Mouse != null)
{
// first we want to create a copy of ourselves without any button changes
// this is done only for mouse handlers, as they have positional data we want to handle in a separate pass.
var iWithoutButtons = state.Mouse.Clone();

for (MouseButton b = 0; b < MouseButton.LastButton; b++)
iWithoutButtons.SetPressed(b, lastMouse?.IsPressed(b) ?? false);

//we start by adding this state to the processed list...
var newState = state.Clone();
newState.Mouse = lastMouse = iWithoutButtons;
yield return newState;

//and then iterate over each button/key change, adding intermediate states along the way.
for (MouseButton b = 0; b < MouseButton.LastButton; b++)
{
if (state.Mouse.IsPressed(b) != (lastMouse?.IsPressed(b) ?? false))
{
lastMouse = lastMouse?.Clone() ?? new MouseState();

//add our single local change
lastMouse.SetPressed(b, state.Mouse.IsPressed(b));

newState = state.Clone();
newState.Mouse = lastMouse;
yield return newState;
}
}
}

if (state.Keyboard != null)
{
if (lastKeyboard != null)
foreach (var releasedKey in lastKeyboard.Keys.Except(state.Keyboard.Keys))
{
var newState = state.Clone();
newState.Keyboard = lastKeyboard = new KeyboardState { Keys = lastKeyboard.Keys.Where(d => d != releasedKey).ToArray() };
yield return newState;
}

foreach (var pressedKey in state.Keyboard.Keys.Except(lastKeyboard?.Keys ?? new Key[] { }))
{
var newState = state.Clone();
newState.Keyboard = lastKeyboard = new KeyboardState { Keys = lastKeyboard?.Keys.Union(new[] { pressedKey }) ?? new[] { pressedKey } };
yield return newState;
}
}
}
}
}

public enum ConfineMouseMode
Expand Down
Loading

0 comments on commit 07aa057

Please sign in to comment.