protected override bool OnHover(InputState state) { expandEvent = Scheduler.AddDelayed(() => { expandEvent = null; ResizeTo(new Vector2(expanded_width, Height), 150, EasingTypes.OutQuad); }, 750); return true; }
private void scheduleUpdateFilter() { scheduledFilterUpdate?.Cancel(); scheduledFilterUpdate = Scheduler.AddDelayed(updateFilter, 200); }
/// <summary> /// selection has been changed as the result of a user interaction. /// </summary> private void performUpdateSelected() { var beatmap = beatmapNoDebounce; var ruleset = rulesetNoDebounce; void run() { Logger.Log($"updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ID.ToString() ?? "null"}"); bool preview = false; if (ruleset?.Equals(Ruleset.Value) == false) { Logger.Log($"ruleset changed from \"{Ruleset.Value}\" to \"{ruleset}\""); Beatmap.Value.Mods.Value = Enumerable.Empty <Mod>(); Ruleset.Value = ruleset; // force a filter before attempting to change the beatmap. // we may still be in the wrong ruleset as there is a debounce delay on ruleset changes. Carousel.Filter(null, false); // Filtering only completes after the carousel runs Update. // If we also have a pending beatmap change we should delay it one frame. selectionChangedDebounce = Schedule(run); return; } // We may be arriving here due to another component changing the bindable Beatmap. // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. if (!Equals(beatmap, Beatmap.Value.BeatmapInfo)) { Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\""); preview = beatmap?.BeatmapSetInfoID != Beatmap.Value?.BeatmapInfo.BeatmapSetInfoID; Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value); if (beatmap != null) { if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) { sampleChangeDifficulty.Play(); } else { sampleChangeBeatmap.Play(); } } } ensurePlayingSelected(preview); UpdateBeatmap(Beatmap.Value); } selectionChangedDebounce?.Cancel(); if (beatmap == null) { run(); } else { selectionChangedDebounce = Scheduler.AddDelayed(run, 200); } }
public override void Reset() { base.Reset(); Add(render3DContainer = new Render3DContainer { RelativeSizeAxes = Axes.Both, BackgroundColour = Color4.White.Scale(0.01f), Children = new Drawable3D[] { new Sprite3D { Colour = Color4.HotPink, Texture = testTexture, BlendingMode = BlendingMode.Mixture, Position = new Vector3(0.0f, 0.0f, 0.0f), Rotation = Quaternion.FromAxisAngle(Vector3.Right, MathHelper.PiOver2) }, particleSystem = new ParticleSystem() { EmissionRate = 300.0f, MaximumParticles = 1000, Texture = testTexture, BlendingMode = BlendingMode.Mixture, Position = new Vector3(0.0f, 0.0f, 0.0f), Rotation = Quaternion.FromAxisAngle(Vector3.Right, -MathHelper.PiOver2), // Facing up VelocityInitializer = new ConeVelocityInitializer { Angle = MathHelper.Pi * 0.4f, MinimumVelocity = 1.0f, MaximumVelocity = 3.0f }, RotationInitializer = new RotationInitializer { Minimum = 0.0f, Maximum = MathHelper.Pi }, SizeInitializer = new SizeInitializer { MaximumUniform = 0.6f, MinimumUniform = 0.4f }, ColourInitializer = new ColourInitializer(Color4.AliceBlue.WithAlpha(0.6f)), ParticleUpdaters = new Updater[] { new ConstantRotationSpeed(), new VelocityDecay(), }, ComputedProperties = new ComputedProperty[] { new AlphaFade(), new SizeFade { Easing = EasingTypes.None, End = 1.0f, Start = 0.2f } }, TransparencyGroup = 3 }, cameraBoom = new Node { Children = new Drawable3D[] { new Camera() { Position = new Vector3(0.0f, 0.0f, 5.0f) } } } } }); cameraRotation = new Vector3(-20.0f, -45.0f, 0.0f); UpdateCamera(); animation = Scheduler.AddDelayed(() => { double phase = Time.Current / 1000.0 * 2.0f; particleSystem.Position = new Vector3((float)Math.Cos(phase), 0.0f, (float)Math.Sin(phase)) * 2.0f; }, 10.0, true); }
private void schedulePopOut() { popOutDelegate?.Cancel(); Delay(1000); popOutDelegate = Schedule(Hide); }
private void scheduleRefresh() { scheduledRefresh?.Cancel(); scheduledRefresh = Schedule(refresh); }
private void cancelPendingStart() { scheduledStart?.Cancel(); scheduledStart = null; }
public void AddScheduledCallback(float delay, ScheduledDelegate callback) { _scheduledCallbacks.Add(new ScheduledDelegateData(callback, delay)); }
/// <summary> /// Handles changes in player state which may progress the completion of gameplay / this screen's lifetime. /// </summary> /// <param name="skipStoryboardOutro">If in a state where a storyboard outro is to be played, offers the choice of skipping beyond it.</param> /// <exception cref="InvalidOperationException">Thrown if this method is called more than once without changing state.</exception> private void updateCompletionState(bool skipStoryboardOutro = false) { // screen may be in the exiting transition phase. if (!this.IsCurrentScreen()) { return; } if (!ScoreProcessor.HasCompleted.Value) { completionProgressDelegate?.Cancel(); completionProgressDelegate = null; ValidForResume = true; skipOutroOverlay.Hide(); return; } if (completionProgressDelegate != null) { throw new InvalidOperationException($"{nameof(updateCompletionState)} was fired more than once"); } // Only show the completion screen if the player hasn't failed if (HealthProcessor.HasFailed) { return; } ValidForResume = false; if (!Configuration.ShowResults) { return; } prepareScoreForDisplayTask ??= Task.Run(async() => { var score = CreateScore(); try { await PrepareScoreForResultsAsync(score).ConfigureAwait(false); } catch (Exception ex) { Logger.Error(ex, "Score preparation failed!"); } try { await ImportScore(score).ConfigureAwait(false); } catch (Exception ex) { Logger.Error(ex, "Score import failed!"); } return(score.ScoreInfo); }); if (skipStoryboardOutro) { scheduleCompletion(); return; } bool storyboardHasOutro = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value; if (storyboardHasOutro) { skipOutroOverlay.Show(); return; } using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) scheduleCompletion(); }
protected override void LoadComplete() { base.LoadComplete(); areaOffset.BindTo(tabletHandler.AreaOffset); areaOffset.BindValueChanged(val => { offsetX.Value = val.NewValue.X; offsetY.Value = val.NewValue.Y; }, true); offsetX.BindValueChanged(val => areaOffset.Value = new Vector2(val.NewValue, areaOffset.Value.Y)); offsetY.BindValueChanged(val => areaOffset.Value = new Vector2(areaOffset.Value.X, val.NewValue)); areaSize.BindTo(tabletHandler.AreaSize); areaSize.BindValueChanged(val => { sizeX.Value = val.NewValue.X; sizeY.Value = val.NewValue.Y; }, true); sizeX.BindValueChanged(val => { areaSize.Value = new Vector2(val.NewValue, areaSize.Value.Y); aspectRatioApplication?.Cancel(); aspectRatioApplication = Schedule(() => applyAspectRatio(sizeX)); }); sizeY.BindValueChanged(val => { areaSize.Value = new Vector2(areaSize.Value.X, val.NewValue); aspectRatioApplication?.Cancel(); aspectRatioApplication = Schedule(() => applyAspectRatio(sizeY)); }); updateAspectRatio(); aspectRatio.BindValueChanged(aspect => { aspectRatioApplication?.Cancel(); aspectRatioApplication = Schedule(() => forceAspectRatio(aspect.NewValue)); }); tablet.BindTo(tabletHandler.Tablet); tablet.BindValueChanged(val => { Scheduler.AddOnce(toggleVisibility); var tab = val.NewValue; bool tabletFound = tab != null; if (!tabletFound) { return; } offsetX.MaxValue = tab.Size.X; offsetX.Default = tab.Size.X / 2; sizeX.Default = sizeX.MaxValue = tab.Size.X; offsetY.MaxValue = tab.Size.Y; offsetY.Default = tab.Size.Y / 2; sizeY.Default = sizeY.MaxValue = tab.Size.Y; areaSize.Default = new Vector2(sizeX.Default, sizeY.Default); }, true); }
public static TransformSequence <T> Schedule <T, TData>(this TransformSequence <T> t, Action <TData> scheduledAction, TData data, out ScheduledDelegate scheduledDelegate) where T : Drawable => t.Append(o => o.Schedule(scheduledAction, data), out scheduledDelegate);
private void runNextStep(Action onCompletion, Action <Exception> onError, Func <StepButton, bool> stopCondition) { try { if (loadableStep != null) { if (loadableStep.IsMaskedAway) { scroll.ScrollTo(loadableStep); } loadableStep.PerformStep(); } } catch (Exception e) { onError?.Invoke(e); return; } string text = "."; if (actionRepetition == 0) { text = $"{(int)Time.Current}: ".PadLeft(7); if (actionIndex < 0) { text += $"{GetType().ReadableName()}"; } else { text += $"step {actionIndex + 1} {loadableStep?.ToString() ?? string.Empty}"; } } Console.Write(text); actionRepetition++; if (actionRepetition > (loadableStep?.RequiredRepetitions ?? 1) - 1) { actionIndex++; actionRepetition = 0; Console.WriteLine(); if (loadableStep != null && stopCondition?.Invoke(loadableStep) == true) { return; } } if (actionIndex > StepsContainer.Children.Count - 1) { onCompletion?.Invoke(); return; } if (Parent != null) { stepRunner = Scheduler.AddDelayed(() => runNextStep(onCompletion, onError, stopCondition), TimePerAction); } }
public Task TakeScreenshotAsync() => Task.Run(async() => { Interlocked.Increment(ref screenShotTasks); if (!captureMenuCursor.Value) { cursorVisibility.Value = false; // We need to wait for at most 3 draw nodes to be drawn, following which we can be assured at least one DrawNode has been generated/drawn with the set value const int frames_to_wait = 3; int framesWaited = 0; ScheduledDelegate waitDelegate = host.DrawThread.Scheduler.AddDelayed(() => framesWaited++, 0, true); while (framesWaited < frames_to_wait) { Thread.Sleep(10); } waitDelegate.Cancel(); } using (var image = await host.TakeScreenshotAsync()) { if (Interlocked.Decrement(ref screenShotTasks) == 0 && cursorVisibility.Value == false) { cursorVisibility.Value = true; } var fileName = getFileName(); if (fileName == null) { return; } var stream = storage.GetStream(fileName, FileAccess.Write); switch (screenshotFormat.Value) { case ScreenshotFormat.Png: image.SaveAsPng(stream); break; case ScreenshotFormat.Jpg: image.SaveAsJpeg(stream); break; default: throw new ArgumentOutOfRangeException(nameof(screenshotFormat)); } notificationOverlay.Post(new SimpleNotification { Text = $"{fileName} saved!", Activated = () => { storage.OpenInNativeExplorer(); return(true); } }); } });
public void OnReleased(KeyBindingReleaseEvent <GlobalAction> e) { scheduledScrollSpeedAdjustment?.Cancel(); scheduledScrollSpeedAdjustment = null; }
public ScheduledDelegateData(ScheduledDelegate callback, float delay) { this.callback = callback; this.delay = delay; }
/// <summary> /// selection has been changed as the result of a user interaction. /// </summary> private void updateSelectedBeatmap(BeatmapInfo beatmap) { var ruleset = base.Ruleset.Value; void performLoad() { WorkingBeatmap working = Beatmap.Value; bool preview = false; // We may be arriving here due to another component changing the bindable Beatmap. // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. if (beatmap?.Equals(Beatmap.Value.BeatmapInfo) != true) { preview = beatmap?.BeatmapSetInfoID != Beatmap.Value?.BeatmapInfo.BeatmapSetInfoID; working = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value); } working.Mods.Value = Enumerable.Empty <Mod>(); Beatmap.Value = working; Ruleset.Value = ruleset; ensurePlayingSelected(preview); UpdateBeatmap(Beatmap.Value); } if (beatmap?.Equals(beatmapNoDebounce) == true && ruleset?.Equals(rulesetNoDebounce) == true) { return; } selectionChangedDebounce?.Cancel(); beatmapNoDebounce = beatmap; rulesetNoDebounce = ruleset; if (beatmap == null) { performLoad(); } else { if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) { sampleChangeDifficulty.Play(); } else { sampleChangeBeatmap.Play(); } if (beatmap == Beatmap.Value.BeatmapInfo) { performLoad(); } else { selectionChangedDebounce = Scheduler.AddDelayed(performLoad, 200); } } }
private void cancelLoad() { scheduledPushPlayer?.Cancel(); scheduledPushPlayer = null; }
private void initializeChannels() { Clear(); careChannels = new List<Channel>(); //if (api.State != APIAccess.APIState.Online) // return; SpriteText loading; Add(loading = new SpriteText { Text = @"Loading available channels...", Anchor = Anchor.Centre, Origin = Anchor.Centre, TextSize = 40, }); messageRequest?.Cancel(); ListChannelsRequest req = new ListChannelsRequest(); req.Success += delegate (List<Channel> channels) { Scheduler.Add(delegate { loading.FadeOut(100); addChannel(channels.Find(c => c.Name == @"#osu")); }); //addChannel(channels.Find(c => c.Name == @"#lobby")); //addChannel(channels.Find(c => c.Name == @"#english")); messageRequest = Scheduler.AddDelayed(() => FetchNewMessages(api), 1000, true); }; api.Queue(req); }
protected void LoadScore(ScoreInfo score, bool silent) { if (silent) { return; } scoreLoad?.Cancel(); var menu = intro.ChildScreen; if (menu == null) { scoreLoad = Schedule(() => LoadScore(score, false)); return; } var databasedScore = ScoreManager.GetScore(score); var databasedScoreInfo = databasedScore.ScoreInfo; if (databasedScore.Replay == null) { Logger.Log("The loaded score has no replay data.", LoggingTarget.Information); return; } var databasedBeatmap = BeatmapManager.QueryBeatmap(b => b.ID == databasedScoreInfo.Beatmap.ID); if (databasedBeatmap == null) { Logger.Log("Tried to load a score for a beatmap we don't have!", LoggingTarget.Information); return; } if (!currentScreen.AllowExternalScreenChange) { notifications.Post(new SimpleNotification { Text = $"Click here to watch {databasedScoreInfo.User.Username} on {databasedScoreInfo.Beatmap}", Activated = () => { loadScore(); return(true); } }); return; } loadScore(); void loadScore() { if (!menu.IsCurrentScreen) { menu.MakeCurrent(); this.Delay(500).Schedule(loadScore, out scoreLoad); return; } ruleset.Value = databasedScoreInfo.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); Beatmap.Value.Mods.Value = databasedScoreInfo.Mods; currentScreen.Push(new PlayerLoader(() => new ReplayPlayer(databasedScore))); } }
public Storage LocateStableStorage() { scheduled?.Cancel(); Storage = null; try { Storage = new StableStorage(host as DesktopGameHost); const string file_ipc_filename = "ipc.txt"; const string file_ipc_state_filename = "ipc-state.txt"; const string file_ipc_scores_filename = "ipc-scores.txt"; const string file_ipc_channel_filename = "ipc-channel.txt"; if (Storage.Exists(file_ipc_filename)) { scheduled = Scheduler.AddDelayed(delegate { try { using (var stream = Storage.GetStream(file_ipc_filename)) using (var sr = new StreamReader(stream)) { var beatmapId = int.Parse(sr.ReadLine()); var mods = int.Parse(sr.ReadLine()); if (lastBeatmapId != beatmapId) { lastBeatmapId = beatmapId; var existing = ladder.CurrentMatch.Value?.Round.Value?.Beatmaps.FirstOrDefault(b => b.ID == beatmapId && b.BeatmapInfo != null); if (existing != null) { Beatmap.Value = existing.BeatmapInfo; } else { var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = beatmapId }); req.Success += b => Beatmap.Value = b.ToBeatmap(Rulesets); API.Queue(req); } } Mods.Value = (LegacyMods)mods; } } catch { // file might be in use. } try { using (var stream = Storage.GetStream(file_ipc_channel_filename)) using (var sr = new StreamReader(stream)) { ChatChannel.Value = sr.ReadLine(); } } catch (Exception) { // file might be in use. } try { using (var stream = Storage.GetStream(file_ipc_state_filename)) using (var sr = new StreamReader(stream)) { State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine()); } } catch (Exception) { // file might be in use. } try { using (var stream = Storage.GetStream(file_ipc_scores_filename)) using (var sr = new StreamReader(stream)) { Score1.Value = int.Parse(sr.ReadLine()); Score2.Value = int.Parse(sr.ReadLine()); } } catch (Exception) { // file might be in use. } }, 250, true); } } catch (Exception e) { Logger.Error(e, "Stable installation could not be found; disabling file based IPC"); } return(Storage); }
private Storage initialiseIPCStorage(string path) { scheduled?.Cancel(); IPCStorage = null; try { if (string.IsNullOrEmpty(path)) { return(null); } IPCStorage = new DesktopStorage(path, host as DesktopGameHost); const string file_ipc_filename = "ipc.txt"; const string file_ipc_state_filename = "ipc-state.txt"; const string file_ipc_scores_filename = "ipc-scores.txt"; const string file_ipc_channel_filename = "ipc-channel.txt"; if (IPCStorage.Exists(file_ipc_filename)) { scheduled = Scheduler.AddDelayed(delegate { try { using (var stream = IPCStorage.GetStream(file_ipc_filename)) using (var sr = new StreamReader(stream)) { int beatmapId = int.Parse(sr.ReadLine().AsNonNull()); int mods = int.Parse(sr.ReadLine().AsNonNull()); if (lastBeatmapId != beatmapId) { beatmapLookupRequest?.Cancel(); lastBeatmapId = beatmapId; var existing = ladder.CurrentMatch.Value?.Round.Value?.Beatmaps.FirstOrDefault(b => b.ID == beatmapId && b.Beatmap != null); if (existing != null) { Beatmap.Value = existing.Beatmap; } else { beatmapLookupRequest = new GetBeatmapRequest(new APIBeatmap { OnlineID = beatmapId }); beatmapLookupRequest.Success += b => Beatmap.Value = b; API.Queue(beatmapLookupRequest); } } Mods.Value = (LegacyMods)mods; } } catch { // file might be in use. } try { using (var stream = IPCStorage.GetStream(file_ipc_channel_filename)) using (var sr = new StreamReader(stream)) { ChatChannel.Value = sr.ReadLine(); } } catch (Exception) { // file might be in use. } try { using (var stream = IPCStorage.GetStream(file_ipc_state_filename)) using (var sr = new StreamReader(stream)) { State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine().AsNonNull()); } } catch (Exception) { // file might be in use. } try { using (var stream = IPCStorage.GetStream(file_ipc_scores_filename)) using (var sr = new StreamReader(stream)) { Score1.Value = int.Parse(sr.ReadLine()); Score2.Value = int.Parse(sr.ReadLine()); } } catch (Exception) { // file might be in use. } }, 250, true); } } catch (Exception e) { Logger.Error(e, "Stable installation could not be found; disabling file based IPC"); } return(IPCStorage); }
public static TransformSequence <T> Schedule <T>(this TransformSequence <T> t, Action scheduledAction, out ScheduledDelegate scheduledDelegate) where T : Drawable => t.Append(o => o.Schedule(scheduledAction), out scheduledDelegate);
public override bool Initialize(GameHost host) { host.Window.MouseEnter += window_MouseEnter; host.Window.MouseLeave += window_MouseLeave; mouseInWindow = host.Window.CursorInWindow; // Get the bindables we need to determine whether to confine the mouse to window or not DesktopGameWindow desktopWindow = host.Window as DesktopGameWindow; if (desktopWindow != null) { confineMode.BindTo(desktopWindow.ConfineMouseMode); windowMode.BindTo(desktopWindow.WindowMode); } Enabled.ValueChanged += enabled => { if (enabled) { host.InputThread.Scheduler.Add(scheduled = new ScheduledDelegate(delegate { if (!host.Window.Visible) { return; } bool useRawInput = mouseInWindow && host.Window.Focused; var state = useRawInput ? OpenTK.Input.Mouse.GetState() : OpenTK.Input.Mouse.GetCursorState(); if (state.Equals(lastState)) { return; } if (useRawInput) { if (!lastState.HasValue) { // when we return from being outside of the window, we want to set the new position of our game cursor // to where the OS cursor is, just once. var cursorState = OpenTK.Input.Mouse.GetCursorState(); var screenPoint = host.Window.PointToClient(new Point(cursorState.X, cursorState.Y)); currentPosition = new Vector2(screenPoint.X, screenPoint.Y); } else { currentPosition += new Vector2(state.X - lastState.Value.X, state.Y - lastState.Value.Y) * (float)sensitivity.Value; // When confining, clamp to the window size. if (confineMode.Value == ConfineMouseMode.Always || confineMode.Value == ConfineMouseMode.Fullscreen && windowMode.Value == WindowMode.Fullscreen) { currentPosition = Vector2.Clamp(currentPosition, Vector2.Zero, new Vector2(host.Window.Width, host.Window.Height)); } // update the windows cursor to match our raw cursor position. // this is important when sensitivity is decreased below 1.0, where we need to ensure the cursor stays withing the window. var screenPoint = host.Window.PointToScreen(new Point((int)currentPosition.X, (int)currentPosition.Y)); OpenTK.Input.Mouse.SetPosition(screenPoint.X, screenPoint.Y); } } else { var screenPoint = host.Window.PointToClient(new Point(state.X, state.Y)); currentPosition = new Vector2(screenPoint.X, screenPoint.Y); } IMouseState newState; // While not focused, let's silently ignore everything but position. if (host.IsActive) { lastState = state; newState = new OpenTKPollMouseState(state, host.IsActive, currentPosition); } else { lastState = null; newState = new UnfocusedMouseState(new OpenTK.Input.MouseState(), host.IsActive, currentPosition); } PendingStates.Enqueue(new InputState { Mouse = newState }); FrameStatistics.Increment(StatisticsCounterType.MouseEvents); }, 0, 0)); } else { scheduled?.Cancel(); lastState = null; } }; Enabled.TriggerChange(); return(true); }
private void updateLogoState(MenuState lastState = MenuState.Initial) { if (logo == null) { return; } switch (state) { case MenuState.Exit: case MenuState.Initial: logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { logoTracking = false; if (game != null) { game.OverlayActivationMode.Value = state == MenuState.Exit ? OverlayActivation.Disabled : OverlayActivation.All; game.Toolbar.Hide(); } logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.Both; logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); logo.ScaleTo(1, 800, Easing.OutExpo); }, buttonArea.Alpha * 150); break; case MenuState.TopLevel: case MenuState.Play: switch (lastState) { case MenuState.TopLevel: // coming from toplevel to play break; case MenuState.Initial: logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.None; bool impact = logo.Scale.X > 0.6f; if (lastState == MenuState.Initial) { logo.ScaleTo(0.5f, 200, Easing.In); } logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In); logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { logoTracking = true; if (impact) { logo.Impact(); } if (game != null) { game.OverlayActivationMode.Value = OverlayActivation.All; game.Toolbar.State = Visibility.Visible; } }, 200); break; default: logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.None; logoTracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; } break; case MenuState.EnteringMode: logoTracking = true; break; } }
protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); animation?.Cancel(); animation = null; }
private void updateLogoState(MenuState lastState = MenuState.Initial) { if (logo == null) { return; } logoDelayedAction?.Cancel(); switch (state) { case MenuState.Exit: case MenuState.Initial: logoTracking = false; logoDelayedAction = Scheduler.AddDelayed(() => { showOverlays.Value = false; logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.Both; logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); logo.ScaleTo(1, 800, Easing.OutExpo); }, 150); break; case MenuState.TopLevel: case MenuState.Play: logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.None; switch (lastState) { case MenuState.TopLevel: // coming from toplevel to play case MenuState.Initial: logoTracking = false; logo.ScaleTo(0.5f, 200, Easing.In); logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In); logoDelayedAction = Scheduler.AddDelayed(() => { logoTracking = true; logo.Impact(); showOverlays.Value = true; }, 200); break; default: logoTracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; } break; case MenuState.EnteringMode: logoTracking = true; break; } }
private void stateChanged(ValueChangedEvent <TourneyState> state) { try { if (state.NewValue == TourneyState.Ranking) { if (warmup.Value) { return; } if (ipc.Score1.Value > ipc.Score2.Value) { currentMatch.Value.Team1Score.Value++; } else { currentMatch.Value.Team2Score.Value++; } } scheduledOperation?.Cancel(); void expand() { chat?.Expand(); using (BeginDelayedSequence(300, true)) { scoreDisplay.FadeIn(100); SongBar.Expanded = true; } } void contract() { SongBar.Expanded = false; scoreDisplay.FadeOut(100); using (chat?.BeginDelayedSequence(500)) chat?.Contract(); } switch (state.NewValue) { case TourneyState.Idle: contract(); const float delay_before_progression = 4000; // if we've returned to idle and the last screen was ranking // we should automatically proceed after a short delay if (lastState == TourneyState.Ranking && !warmup.Value) { if (currentMatch.Value?.Completed.Value == true) { scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(TeamWinScreen)); }, delay_before_progression); } else if (currentMatch.Value?.Completed.Value == false) { scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(MapPoolScreen)); }, delay_before_progression); } } break; case TourneyState.Ranking: scheduledOperation = Scheduler.AddDelayed(contract, 10000); break; default: chat.Expand(); expand(); break; } } finally { lastState = state.NewValue; } }
private void buildTest() { Add(new Container { Padding = new MarginPadding(25f), RelativeSizeAxes = Axes.Both, Children = new Drawable[] { fillContainer = new FillFlowContainer { RelativeSizeAxes = Axes.Both, AutoSizeAxes = Axes.None, }, new Box { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, Size = new Vector2(3, 1), Colour = Color4.HotPink, }, new Box { Anchor = Anchor.CentreRight, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, Size = new Vector2(3, 1), Colour = Color4.HotPink, }, new Box { Anchor = Anchor.TopCentre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, Size = new Vector2(1, 3), Colour = Color4.HotPink, }, new Box { Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, Size = new Vector2(1, 3), Colour = Color4.HotPink, } } }); AddToggleStep("Rotate Container", state => { fillContainer.RotateTo(state ? 45f : 0, 1000); }); AddToggleStep("Scale Container", state => { fillContainer.ScaleTo(state ? 1.2f : 1f, 1000); }); AddToggleStep("Shear Container", state => { fillContainer.Shear = state ? new Vector2(0.5f, 0f) : new Vector2(0f, 0f); }); AddToggleStep("Center Container Anchor", state => { fillContainer.Anchor = state ? Anchor.Centre : Anchor.TopLeft; }); AddToggleStep("Center Container Origin", state => { fillContainer.Origin = state ? Anchor.Centre : Anchor.TopLeft; }); AddToggleStep("Autosize Container", state => { if (state) { fillContainer.RelativeSizeAxes = Axes.None; fillContainer.AutoSizeAxes = Axes.Both; } else { fillContainer.AutoSizeAxes = Axes.None; fillContainer.RelativeSizeAxes = Axes.Both; fillContainer.Width = 1; fillContainer.Height = 1; } }); AddToggleStep("Rotate children", state => { if (state) { foreach (var child in fillContainer.Children) { child.RotateTo(45f, 1000); } } else { foreach (var child in fillContainer.Children) { child.RotateTo(0f, 1000); } } }); AddToggleStep("Shear children", state => { if (state) { foreach (var child in fillContainer.Children) { child.Shear = new Vector2(0.2f, 0.2f); } } else { foreach (var child in fillContainer.Children) { child.Shear = Vector2.Zero; } } }); AddToggleStep("Scale children", state => { if (state) { foreach (var child in fillContainer.Children) { child.ScaleTo(1.25f, 1000); } } else { foreach (var child in fillContainer.Children) { child.ScaleTo(1f, 1000); } } }); AddToggleStep("Randomly scale children", state => { if (state) { foreach (var child in fillContainer.Children) { child.ScaleTo(RNG.NextSingle(1, 2), 1000); } } else { foreach (var child in fillContainer.Children) { child.ScaleTo(1f, 1000); } } }); AddToggleStep("Randomly set child origins", state => { if (state) { foreach (var child in fillContainer.Children) { switch (RNG.Next(9)) { case 0: child.Origin = Anchor.TopLeft; break; case 1: child.Origin = Anchor.TopCentre; break; case 2: child.Origin = Anchor.TopRight; break; case 3: child.Origin = Anchor.CentreLeft; break; case 4: child.Origin = Anchor.Centre; break; case 5: child.Origin = Anchor.CentreRight; break; case 6: child.Origin = Anchor.BottomLeft; break; case 7: child.Origin = Anchor.BottomCentre; break; case 8: child.Origin = Anchor.BottomRight; break; } } } else { foreach (var child in fillContainer.Children) { child.Origin = originDropdown.Current.Value; } } }); AddToggleStep("Stop adding children", state => { doNotAddChildren = state; }); scheduledAdder?.Cancel(); scheduledAdder = Scheduler.AddDelayed( () => { if (fillContainer.Parent == null) { scheduledAdder.Cancel(); } if (doNotAddChildren) { fillContainer.Invalidate(); } if (fillContainer.Children.Count < 1000 && !doNotAddChildren) { fillContainer.Add(new Container { Anchor = childAnchor, Origin = childOrigin, AutoSizeAxes = Axes.Both, Children = new Drawable[] { new Box { Width = 50, Height = 50, Colour = Color4.White }, new SpriteText { Colour = Color4.Black, RelativePositionAxes = Axes.Both, Position = new Vector2(0.5f, 0.5f), Origin = Anchor.Centre, Text = fillContainer.Children.Count.ToString() } } }); } }, 100, true ); }
private void cancelLoad() { pushDebounce?.Cancel(); pushDebounce = null; }
private FillFlowContainer buildTest(FillDirection dir, Vector2 spacing) { ButtonsContainer.RemoveAll(btn => btn != selectionDropdown); FillFlowContainer fc; var cnt = new Container() { Padding = new MarginPadding(25f) { Top = 100f }, RelativeSizeAxes = Axes.Both, Children = new[] { fc = new FillFlowContainer() { RelativeSizeAxes = Axes.Both, AutoSizeAxes = Axes.None, Direction = dir, Spacing = spacing, } } }; Add(cnt); var rotateBtn = AddButton("Rotate Container", () => { if (fc.Rotation > 0) { fc.RotateTo(0f, 1000); } else { fc.RotateTo(45f, 1000); } }); AddButton("Scale Container", () => { if (fc.Scale.X == 1f) { fc.ScaleTo(1.2f, 1000); } else { fc.ScaleTo(1f, 1000); } }); AddButton("Shear Container", () => { if (fc.Shear.X == 0) { fc.Shear = new Vector2(0.5f, 0f); } else { fc.Shear = new Vector2(0f, 0f); } }); AddToggle("Center Container Anchor", (state) => { if (state) { fc.Anchor = Anchor.Centre; } else { fc.Anchor = Anchor.TopLeft; } }); AddToggle("Center Container Origin", (state) => { if (state) { fc.Origin = Anchor.Centre; } else { fc.Origin = Anchor.TopLeft; } }); AddToggle("Autosize Container", (state) => { if (state) { fc.RelativeSizeAxes = Axes.None; fc.AutoSizeAxes = Axes.Both; } else { fc.AutoSizeAxes = Axes.None; fc.RelativeSizeAxes = Axes.Both; fc.Width = 1; fc.Height = 1; } }); AddToggle("Anchor TopCenter children", (state) => { if (state) { foreach (var child in fc.Children) { child.Anchor = Anchor.TopCentre; } } else { foreach (var child in fc.Children) { child.Anchor = Anchor.TopLeft; } } }); AddToggle("Rotate children", (state) => { if (state) { foreach (var child in fc.Children) { child.RotateTo(45f, 1000); } } else { foreach (var child in fc.Children) { child.RotateTo(0f, 1000); } } }); AddToggle("Shear children", (state) => { if (state) { foreach (var child in fc.Children) { child.Shear = new Vector2(0.2f, 0.2f); } } else { foreach (var child in fc.Children) { child.Shear = Vector2.Zero; } } }); AddToggle("Scale children", (state) => { if (state) { foreach (var child in fc.Children) { child.ScaleTo(1.25f, 1000); } } else { foreach (var child in fc.Children) { child.ScaleTo(1f, 1000); } } }); AddToggle("Change children origin", (state) => { if (state) { foreach (var child in fc.Children) { child.Origin = Anchor.Centre; } } else { foreach (var child in fc.Children) { child.Origin = Anchor.TopLeft; } } }); var addChildrenBtn = AddToggle("Stop adding children", (state) => { }); cnt.Position = new Vector2(rotateBtn.Width, 0f); cnt.Padding = new MarginPadding(25f) { Top = cnt.Padding.Top, Right = 25f + cnt.Position.X }; Add(new Box { Colour = Color4.HotPink, Width = 3, Height = 3, Position = fc.Parent.ToSpaceOfOtherDrawable(fc.BoundingBox.TopLeft, this), Origin = Anchor.Centre }); Add(new Box { Colour = Color4.HotPink, Width = 3, Height = 3, Position = fc.Parent.ToSpaceOfOtherDrawable(fc.BoundingBox.TopRight, this), Origin = Anchor.Centre }); Add(new Box { Colour = Color4.HotPink, Width = 3, Height = 3, Position = fc.Parent.ToSpaceOfOtherDrawable(fc.BoundingBox.BottomLeft, this), Origin = Anchor.Centre }); Add(new Box { Colour = Color4.HotPink, Width = 3, Height = 3, Position = fc.Parent.ToSpaceOfOtherDrawable(fc.BoundingBox.BottomRight, this), Origin = Anchor.Centre }); ScheduledDelegate d = null; d = Scheduler.AddDelayed( () => { if (fc.Parent == null) { d.Cancel(); } if (addChildrenBtn.State) { fc.Invalidate(); } if (fc.Children.Count() < 1000 && !addChildrenBtn.State) { fc.Add(new Container { AutoSizeAxes = Axes.Both, Children = new Drawable[] { new Box { Width = 50, Height = 50, Colour = new Color4(255, 255, 255, 255) }, new SpriteText { Colour = Color4.Black, RelativePositionAxes = Axes.Both, Position = new Vector2(0.5f, 0.5f), Origin = Anchor.Centre, Text = fc.Children.Count().ToString() } } }); } }, 100, true ); return(fc); }
private void updateCompletionState(ValueChangedEvent <bool> completionState) { // screen may be in the exiting transition phase. if (!this.IsCurrentScreen()) { return; } if (!completionState.NewValue) { completionProgressDelegate?.Cancel(); completionProgressDelegate = null; ValidForResume = true; return; } if (completionProgressDelegate != null) { throw new InvalidOperationException($"{nameof(updateCompletionState)} was fired more than once"); } // Only show the completion screen if the player hasn't failed if (HealthProcessor.HasFailed) { return; } ValidForResume = false; if (!Configuration.ShowResults) { return; } scoreSubmissionTask ??= Task.Run(async() => { var score = CreateScore(); try { await SubmitScore(score); } catch (Exception ex) { Logger.Error(ex, "Score submission failed!"); } try { await ImportScore(score); } catch (Exception ex) { Logger.Error(ex, "Score import failed!"); } return(score.ScoreInfo); }); using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) scheduleCompletion(); }
public override bool Initialize(GameHost host) { base.Initialize(host); // Get the bindables we need to determine whether to confine the mouse to window or not if (host.Window is DesktopGameWindow desktopWindow) { confineMode.BindTo(desktopWindow.ConfineMouseMode); windowMode.BindTo(desktopWindow.WindowMode); mapAbsoluteInputToWindow.BindTo(desktopWindow.MapAbsoluteInputToWindow); } Enabled.BindValueChanged(e => { if (e.NewValue) { host.InputThread.Scheduler.Add(scheduled = new ScheduledDelegate(delegate { if (!host.Window.Visible || host.Window.WindowState == WindowState.Minimized) { return; } if ((MouseInWindow || lastEachDeviceStates.Any(s => s != null && s.Buttons.HasAnyButtonPressed)) && host.Window.Focused) { osuTK.Input.Mouse.GetStates(newRawStates); while (lastEachDeviceStates.Count < newRawStates.Count) { lastEachDeviceStates.Add(null); } for (int i = 0; i < newRawStates.Count; i++) { if (newRawStates[i].IsConnected != true) { lastEachDeviceStates[i] = null; continue; } var rawState = newRawStates[i]; var lastState = lastEachDeviceStates[i]; if (lastState != null && rawState.Equals(lastState.RawState)) { continue; } var newState = new OsuTKPollMouseState(rawState, host.IsActive.Value, getUpdatedPosition(rawState, lastState)); HandleState(newState, lastState, rawState.Flags.HasFlag(MouseStateFlags.MoveAbsolute)); lastEachDeviceStates[i] = newState; lastUnfocusedState = null; } } else { var state = osuTK.Input.Mouse.GetCursorState(); var screenPoint = host.Window.PointToClient(new Point(state.X, state.Y)); var newState = new UnfocusedMouseState(new MouseState(), host.IsActive.Value, new Vector2(screenPoint.X, screenPoint.Y)); HandleState(newState, lastUnfocusedState, true); lastUnfocusedState = newState; lastEachDeviceStates.Clear(); } }, 0, 0)); } else { scheduled?.Cancel(); lastEachDeviceStates.Clear(); lastUnfocusedState = null; } }, true); return(true); }
private void pushWhenLoaded() { if (!this.IsCurrentScreen()) { return; } if (!readyForPush) { // as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce // if we become unready for push during the delay. cancelLoad(); return; } // if a push has already been scheduled, no further action is required. // this value is reset via cancelLoad() to allow a second usage of the same PlayerLoader screen. if (scheduledPushPlayer != null) { return; } scheduledPushPlayer = Scheduler.AddDelayed(() => { // ensure that once we have reached this "point of no return", readyForPush will be false for all future checks (until a new player instance is prepared). var consumedPlayer = consumePlayer(); ContentOut(); TransformSequence <PlayerLoader> pushSequence = this.Delay(CONTENT_OUT_DURATION); // only show if the warning was created (i.e. the beatmap needs it) // and this is not a restart of the map (the warning expires after first load). if (epilepsyWarning?.IsAlive == true) { const double epilepsy_display_length = 3000; pushSequence .Schedule(() => epilepsyWarning.State.Value = Visibility.Visible) .TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint) .Delay(epilepsy_display_length) .Schedule(() => { epilepsyWarning.Hide(); epilepsyWarning.Expire(); }) .Delay(EpilepsyWarning.FADE_DURATION); } else { // This goes hand-in-hand with the restoration of low pass filter in contentOut(). this.TransformBindableTo(volumeAdjustment, 0, CONTENT_OUT_DURATION, Easing.OutCubic); } pushSequence.Schedule(() => { if (!this.IsCurrentScreen()) { return; } LoadTask = null; // By default, we want to load the player and never be returned to. // Note that this may change if the player we load requested a re-run. ValidForResume = false; if (consumedPlayer.LoadedBeatmapSuccessfully) { this.Push(consumedPlayer); } else { this.Exit(); } }); }, 500); }
public Task TakeScreenshotAsync() => Task.Run(async() => { Interlocked.Increment(ref screenShotTasks); if (!captureMenuCursor.Value) { cursorVisibility.Value = false; // We need to wait for at most 3 draw nodes to be drawn, following which we can be assured at least one DrawNode has been generated/drawn with the set value const int frames_to_wait = 3; int framesWaited = 0; using (var framesWaitedEvent = new ManualResetEventSlim(false)) { ScheduledDelegate waitDelegate = host.DrawThread.Scheduler.AddDelayed(() => { if (framesWaited++ >= frames_to_wait) { // ReSharper disable once AccessToDisposedClosure framesWaitedEvent.Set(); } }, 10, true); framesWaitedEvent.Wait(); waitDelegate.Cancel(); } } using (var image = await host.TakeScreenshotAsync()) { if (Interlocked.Decrement(ref screenShotTasks) == 0 && cursorVisibility.Value == false) { cursorVisibility.Value = true; } var fileName = getFileName(); if (fileName == null) { return; } var stream = storage.GetStream(fileName, FileAccess.Write); switch (screenshotFormat.Value) { case ScreenshotFormat.Png: image.SaveAsPng(stream); break; case ScreenshotFormat.Jpg: const int jpeg_quality = 92; image.SaveAsJpeg(stream, new JpegEncoder { Quality = jpeg_quality }); break; default: throw new InvalidOperationException($"Unknown enum member {nameof(ScreenshotFormat)} {screenshotFormat.Value}."); } notificationOverlay.Post(new SimpleNotification { Text = $"{fileName} saved!", Activated = () => { storage.OpenInNativeExplorer(); return(true); } }); } });
private void initializeChannels() { careChannels = new List<Channel>(); if (api.State != APIState.Online) return; Add(flow = new FlowContainer { RelativeSizeAxes = Axes.Both, Direction = FlowDirection.VerticalOnly }); SpriteText loading; Add(loading = new SpriteText { Text = @"Loading available channels...", Anchor = Anchor.Centre, Origin = Anchor.Centre, TextSize = 40, }); messageRequest?.Cancel(); ListChannelsRequest req = new ListChannelsRequest(); req.Success += delegate (List<Channel> channels) { Scheduler.Add(delegate { loading.FadeOut(100); }); addChannel(channels.Find(c => c.Name == @"#osu")); addChannel(channels.Find(c => c.Name == @"#lobby")); addChannel(channels.Find(c => c.Name == @"#english")); messageRequest = scheduler.AddDelayed(() => FetchNewMessages(api), 1000, true); }; api.Queue(req); }