private void updateSize() { const float fade_time = 500; if (targetMode == ScalingMode.Everything) { // the top level scaling container manages the background to be displayed while scaling. if (requiresBackgroundVisible) { if (backgroundStack == null) { AddInternal(backgroundStack = new BackgroundScreenStack { Colour = OsuColour.Gray(0.1f), Alpha = 0, Depth = float.MaxValue }); backgroundStack.Push(new ScalingBackgroundScreen()); } backgroundStack.FadeIn(fade_time); } else { backgroundStack?.FadeOut(fade_time); } } bool scaling = targetMode == null || scalingMode.Value == targetMode; var targetSize = scaling ? new Vector2(sizeX.Value, sizeY.Value) : Vector2.One; var targetPosition = scaling ? new Vector2(posX.Value, posY.Value) * (Vector2.One - targetSize) : Vector2.Zero; bool requiresMasking = scaling && targetSize != Vector2.One; if (requiresMasking) { sizableContainer.Masking = true; } sizableContainer.MoveTo(targetPosition, 500, Easing.OutQuart); sizableContainer.ResizeTo(targetSize, 500, Easing.OutQuart).OnComplete(_ => { sizableContainer.Masking = requiresMasking; }); }
public void SetUpSteps() { AddStep("create background stack", () => Child = stack = new BackgroundScreenStack()); AddStep("push default screen", () => stack.Push(screen = new BackgroundScreenDefault(false))); AddUntilStep("wait for screen to load", () => screen.IsCurrentScreen()); }
protected override void LoadComplete() { base.LoadComplete(); // The next time this is updated is in UpdateAfterChildren, which occurs too late and results // in the cursor being shown for a few frames during the intro. // This prevents the cursor from showing until we have a screen with CursorVisible = true MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false; // todo: all archive managers should be able to be looped here. SkinManager.PostNotification = n => notifications?.Post(n); SkinManager.GetStableStorage = GetStorageForStableInstall; BeatmapManager.PostNotification = n => notifications?.Post(n); BeatmapManager.GetStableStorage = GetStorageForStableInstall; BeatmapManager.PresentImport = items => PresentBeatmap(items.First()); ScoreManager.PostNotification = n => notifications?.Post(n); ScoreManager.PresentImport = items => PresentScore(items.First()); Container logoContainer; AddRange(new Drawable[] { new VolumeControlReceptor { RelativeSizeAxes = Axes.Both, ActionRequested = action => volume.Adjust(action), ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise), }, screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays) { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { backgroundParallax = new ParallaxContainer { RelativeSizeAxes = Axes.Both, Child = backgroundStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both }, }, screenStack = new ScreenStack { RelativeSizeAxes = Axes.Both }, logoContainer = new Container { RelativeSizeAxes = Axes.Both }, } }, overlayContent = new Container { RelativeSizeAxes = Axes.Both, }, floatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue }, idleTracker = new GameIdleTracker(6000) }); dependencies.Cache(backgroundStack); screenStack.ScreenPushed += screenPushed; screenStack.ScreenExited += screenExited; loadComponentSingleFile(osuLogo, logoContainer.Add); loadComponentSingleFile(new Loader { RelativeSizeAxes = Axes.Both }, screenStack.Push); loadComponentSingleFile(Toolbar = new Toolbar { Depth = -5, OnHome = delegate { CloseAllOverlays(false); menuScreen?.MakeCurrent(); }, }, floatingOverlayContent.Add); loadComponentSingleFile(volume = new VolumeOverlay(), floatingOverlayContent.Add); loadComponentSingleFile(onscreenDisplay = new OnScreenDisplay(), Add); loadComponentSingleFile(screenshotManager, Add); //overlay elements loadComponentSingleFile(direct = new DirectOverlay { Depth = -1 }, overlayContent.Add); loadComponentSingleFile(social = new SocialOverlay { Depth = -1 }, overlayContent.Add); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal); loadComponentSingleFile(chatOverlay = new ChatOverlay { Depth = -1 }, overlayContent.Add); loadComponentSingleFile(settings = new MainSettings { GetToolbarHeight = () => ToolbarOffset, Depth = -1 }, floatingOverlayContent.Add); loadComponentSingleFile(userProfile = new UserProfileOverlay { Depth = -2 }, overlayContent.Add); loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay { Depth = -3 }, overlayContent.Add); loadComponentSingleFile(musicController = new MusicController { Depth = -5, Position = new Vector2(0, Toolbar.HEIGHT), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, floatingOverlayContent.Add); loadComponentSingleFile(notifications = new NotificationOverlay { GetToolbarHeight = () => ToolbarOffset, Depth = -4, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, floatingOverlayContent.Add); loadComponentSingleFile(accountCreation = new AccountCreationOverlay { Depth = -6, }, floatingOverlayContent.Add); loadComponentSingleFile(dialogOverlay = new DialogOverlay { Depth = -7, }, floatingOverlayContent.Add); loadComponentSingleFile(externalLinkOpener = new ExternalLinkOpener { Depth = -8, }, floatingOverlayContent.Add); dependencies.CacheAs(idleTracker); dependencies.Cache(settings); dependencies.Cache(onscreenDisplay); dependencies.Cache(social); dependencies.Cache(direct); dependencies.Cache(chatOverlay); dependencies.Cache(channelManager); dependencies.Cache(userProfile); dependencies.Cache(musicController); dependencies.Cache(beatmapSetOverlay); dependencies.Cache(notifications); dependencies.Cache(dialogOverlay); dependencies.Cache(accountCreation); chatOverlay.StateChanged += state => channelManager.HighPollRate.Value = state == Visibility.Visible; Add(externalLinkOpener = new ExternalLinkOpener()); var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications }; overlays.AddRange(singleDisplaySideOverlays); foreach (var overlay in singleDisplaySideOverlays) { overlay.StateChanged += state => { if (state == Visibility.Hidden) { return; } singleDisplaySideOverlays.Where(o => o != overlay).ForEach(o => o.Hide()); }; } // eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time. var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile }; overlays.AddRange(informationalOverlays); foreach (var overlay in informationalOverlays) { overlay.StateChanged += state => { if (state == Visibility.Hidden) { return; } informationalOverlays.Where(o => o != overlay).ForEach(o => o.Hide()); }; } // ensure only one of these overlays are open at once. var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct }; overlays.AddRange(singleDisplayOverlays); foreach (var overlay in singleDisplayOverlays) { overlay.StateChanged += state => { // informational overlays should be dismissed on a show or hide of a full overlay. informationalOverlays.ForEach(o => o.Hide()); if (state == Visibility.Hidden) { return; } singleDisplayOverlays.Where(o => o != overlay).ForEach(o => o.Hide()); }; } OverlayActivationMode.ValueChanged += mode => { if (mode.NewValue != OverlayActivation.All) { CloseAllOverlays(); } }; void updateScreenOffset() { float offset = 0; if (settings.State == Visibility.Visible) { offset += ToolbarButton.WIDTH / 2; } if (notifications.State == Visibility.Visible) { offset -= ToolbarButton.WIDTH / 2; } screenContainer.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); } settings.StateChanged += _ => updateScreenOffset(); notifications.StateChanged += _ => updateScreenOffset(); }
private void updateSize() { if (targetMode == ScalingMode.Everything) { // the top level scaling container manages the background to be displayed while scaling. if (requiresBackgroundVisible) { if (backgroundStack == null) { AddInternal(backgroundStack = new BackgroundScreenStack { Colour = OsuColour.Gray(0.1f), Alpha = 0, Depth = float.MaxValue }); backgroundStack.Push(new ScalingBackgroundScreen()); } backgroundStack.FadeIn(duration); } else { backgroundStack?.FadeOut(duration); } } RectangleF targetRect = new RectangleF(Vector2.Zero, Vector2.One); if (customRect != null) { sizableContainer.RelativePositionAxes = customRectIsRelativePosition ? Axes.Both : Axes.None; targetRect = customRect.Value; } else if (targetMode == null || scalingMode.Value == targetMode) { sizableContainer.RelativePositionAxes = Axes.Both; Vector2 scale = new Vector2(sizeX.Value, sizeY.Value); Vector2 pos = new Vector2(posX.Value, posY.Value) * (Vector2.One - scale); targetRect = new RectangleF(pos, scale); } bool requiresMasking = targetRect.Size != Vector2.One // For the top level scaling container, for now we apply masking if safe areas are in use. // In the future this can likely be removed as more of the actual UI supports overflowing into the safe areas. || (targetMode == ScalingMode.Everything && safeAreaPadding.Value.Total != Vector2.Zero); if (requiresMasking) { sizableContainer.Masking = true; } sizableContainer.MoveTo(targetRect.Location, duration, Easing.OutQuart); sizableContainer.ResizeTo(targetRect.Size, duration, Easing.OutQuart); // Of note, this will not work great in the case of nested ScalingContainers where multiple are applying corner radius. // Masking and corner radius should likely only be applied at one point in the full game stack to fix this. // An example of how this can occur is when the skin editor is visible and the game screen scaling is set to "Everything". sizableContainer.TransformTo(nameof(CornerRadius), requiresMasking ? corner_radius : 0, duration, requiresMasking ? Easing.OutQuart : Easing.None) .OnComplete(_ => { sizableContainer.Masking = requiresMasking; }); }