Beispiel #1
0
        /// <summary>
        /// Adds a <see cref="ScoreInfo"/> to this list.
        /// </summary>
        /// <param name="score">The <see cref="ScoreInfo"/> to add.</param>
        /// <param name="isNewLocalScore">Whether this is a score that has just been achieved locally. Controls whether flair is added to the display or not.</param>
        public ScorePanel AddScore(ScoreInfo score, bool isNewLocalScore = false)
        {
            var panel = new ScorePanel(score, isNewLocalScore)
            {
                Anchor           = Anchor.CentreLeft,
                Origin           = Anchor.CentreLeft,
                PostExpandAction = () => PostExpandAction?.Invoke()
            }.With(p =>
            {
                p.StateChanged += s =>
                {
                    if (s == PanelState.Expanded)
                    {
                        SelectedScore.Value = p.Score;
                    }
                };
            });

            var trackingContainer = panel.CreateTrackingContainer().With(d =>
            {
                d.Anchor = Anchor.Centre;
                d.Origin = Anchor.Centre;
                d.Hide();
            });

            flow.Add(trackingContainer);

            if (IsLoaded)
            {
                displayScore(trackingContainer);
            }

            return(panel);
        }
Beispiel #2
0
        /// <summary>
        /// Brings a <see cref="ScoreInfo"/> to the centre of the screen and expands it.
        /// </summary>
        /// <param name="score">The <see cref="ScoreInfo"/> to present.</param>
        private void selectedScoreChanged(ValueChangedEvent <ScoreInfo> score)
        {
            // Contract the old panel.
            foreach (var p in flow.Where(p => p.Score == score.OldValue))
            {
                p.State  = PanelState.Contracted;
                p.Margin = new MarginPadding();
            }

            // Find the panel corresponding to the new score.
            expandedPanel = flow.SingleOrDefault(p => p.Score == score.NewValue);

            // handle horizontal scroll only when not hovering the expanded panel.
            scroll.HandleScroll = () => expandedPanel?.IsHovered != true;

            if (expandedPanel == null)
            {
                return;
            }

            // Expand the new panel.
            expandedPanel.State  = PanelState.Expanded;
            expandedPanel.Margin = new MarginPadding {
                Horizontal = expanded_panel_spacing
            };

            // Scroll to the new panel. This is done manually since we need:
            // 1) To scroll after the scroll container's visible range is updated.
            // 2) To account for the centre anchor/origins of panels.
            // In the end, it's easier to compute the scroll position manually.
            float scrollOffset = flow.GetPanelIndex(expandedPanel.Score) * (ScorePanel.CONTRACTED_WIDTH + panel_spacing);

            scroll.ScrollTo(scrollOffset);
        }
        /// <summary>
        /// Brings a <see cref="ScoreInfo"/> to the centre of the screen and expands it.
        /// </summary>
        /// <param name="score">The <see cref="ScoreInfo"/> to present.</param>
        private void selectedScoreChanged(ValueChangedEvent <ScoreInfo> score)
        {
            // Contract the old panel.
            foreach (var t in flow.Where(t => t.Panel.Score == score.OldValue))
            {
                t.Panel.State = PanelState.Contracted;
                t.Margin      = new MarginPadding();
            }

            // Find the panel corresponding to the new score.
            var expandedTrackingComponent = flow.SingleOrDefault(t => t.Panel.Score == score.NewValue);

            expandedPanel = expandedTrackingComponent?.Panel;

            if (expandedPanel == null)
            {
                return;
            }

            Debug.Assert(expandedTrackingComponent != null);

            // Expand the new panel.
            expandedTrackingComponent.Margin = new MarginPadding {
                Horizontal = expanded_panel_spacing
            };
            expandedPanel.State = PanelState.Expanded;

            // Scroll to the new panel. This is done manually since we need:
            // 1) To scroll after the scroll container's visible range is updated.
            // 2) To account for the centre anchor/origins of panels.
            // In the end, it's easier to compute the scroll position manually.
            float scrollOffset = flow.GetPanelIndex(expandedPanel.Score) * (ScorePanel.CONTRACTED_WIDTH + panel_spacing);

            scroll.ScrollTo(scrollOffset);
        }
Beispiel #4
0
        private void onStatisticsStateChanged(ValueChangedEvent <Visibility> state)
        {
            if (state.NewValue == Visibility.Visible)
            {
                // Detach the panel in its original location, and move into the desired location in the local container.
                var expandedPanel  = ScorePanelList.GetPanelForScore(SelectedScore.Value);
                var screenSpacePos = expandedPanel.ScreenSpaceDrawQuad.TopLeft;

                // Detach and move into the local container.
                ScorePanelList.Detach(expandedPanel);
                detachedPanelContainer.Add(expandedPanel);

                // Move into its original location in the local container first, then to the final location.
                var origLocation = detachedPanelContainer.ToLocalSpace(screenSpacePos).X;
                expandedPanel.MoveToX(origLocation)
                .Then()
                .MoveToX(StatisticsPanel.SIDE_PADDING, 150, Easing.OutQuint);

                // Hide contracted panels.
                foreach (var contracted in ScorePanelList.GetScorePanels().Where(p => p.State == PanelState.Contracted))
                {
                    contracted.FadeOut(150, Easing.OutQuint);
                }
                ScorePanelList.HandleInput = false;

                // Dim background.
                ApplyToBackground(b => b.FadeTo(0.1f, 150));

                detachedPanel = expandedPanel;
            }
            else if (detachedPanel != null)
            {
                var screenSpacePos = detachedPanel.ScreenSpaceDrawQuad.TopLeft;

                // Remove from the local container and re-attach.
                detachedPanelContainer.Remove(detachedPanel);
                ScorePanelList.Attach(detachedPanel);

                // Move into its original location in the attached container first, then to the final location.
                var origLocation = detachedPanel.Parent.ToLocalSpace(screenSpacePos);
                detachedPanel.MoveTo(origLocation)
                .Then()
                .MoveTo(new Vector2(0, origLocation.Y), 150, Easing.OutQuint);

                // Show contracted panels.
                foreach (var contracted in ScorePanelList.GetScorePanels().Where(p => p.State == PanelState.Contracted))
                {
                    contracted.FadeIn(150, Easing.OutQuint);
                }
                ScorePanelList.HandleInput = true;

                // Un-dim background.
                ApplyToBackground(b => b.FadeTo(0.5f, 150));

                detachedPanel = null;
            }
        }
Beispiel #5
0
        /// <summary>
        /// Adds a <see cref="ScoreInfo"/> to this list.
        /// </summary>
        /// <param name="score">The <see cref="ScoreInfo"/> to add.</param>
        /// <param name="isNewLocalScore">Whether this is a score that has just been achieved locally. Controls whether flair is added to the display or not.</param>
        public ScorePanel AddScore(ScoreInfo score, bool isNewLocalScore = false)
        {
            var panel = new ScorePanel(score, isNewLocalScore)
            {
                Anchor           = Anchor.CentreLeft,
                Origin           = Anchor.CentreLeft,
                PostExpandAction = () => PostExpandAction?.Invoke()
            }.With(p =>
            {
                p.StateChanged += s =>
                {
                    if (s == PanelState.Expanded)
                    {
                        SelectedScore.Value = p.Score;
                    }
                };
            });

            flow.Add(panel.CreateTrackingContainer().With(d =>
            {
                d.Anchor = Anchor.Centre;
                d.Origin = Anchor.Centre;
            }));

            if (IsLoaded)
            {
                if (SelectedScore.Value == score)
                {
                    SelectedScore.TriggerChange();
                }
                else
                {
                    // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done.
                    // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel.
                    if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score))
                    {
                        // A somewhat hacky property is used here because we need to:
                        // 1) Scroll after the scroll container's visible range is updated.
                        // 2) Scroll before the scroll container's scroll position is updated.
                        // Without this, we would have a 1-frame positioning error which looks very jarring.
                        scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing;
                    }
                }
            }

            return(panel);
        }
Beispiel #6
0
        /// <summary>
        /// Brings a <see cref="ScoreInfo"/> to the centre of the screen and expands it.
        /// </summary>
        /// <param name="score">The <see cref="ScoreInfo"/> to present.</param>
        private void selectedScoreChanged(ValueChangedEvent <ScoreInfo> score)
        {
            // avoid contracting panels unnecessarily when TriggerChange is fired manually.
            if (score.OldValue != null && !score.OldValue.Equals(score.NewValue))
            {
                // Contract the old panel.
                foreach (var t in flow.Where(t => t.Panel.Score.Equals(score.OldValue)))
                {
                    t.Panel.State = PanelState.Contracted;
                    t.Margin      = new MarginPadding();
                }
            }

            // Find the panel corresponding to the new score.
            var expandedTrackingComponent = flow.SingleOrDefault(t => t.Panel.Score.Equals(score.NewValue));

            expandedPanel = expandedTrackingComponent?.Panel;

            if (expandedPanel == null)
            {
                return;
            }

            Debug.Assert(expandedTrackingComponent != null);

            // Expand the new panel.
            expandedTrackingComponent.Margin = new MarginPadding {
                Horizontal = expanded_panel_spacing
            };
            expandedPanel.State = PanelState.Expanded;

            // requires schedule after children to ensure the flow (and thus ScrollContainer's ScrollableExtent) has been updated.
            ScheduleAfterChildren(() =>
            {
                // Scroll to the new panel. This is done manually since we need:
                // 1) To scroll after the scroll container's visible range is updated.
                // 2) To account for the centre anchor/origins of panels.
                // In the end, it's easier to compute the scroll position manually.
                float scrollOffset = flow.GetPanelIndex(expandedPanel.Score) * (ScorePanel.CONTRACTED_WIDTH + panel_spacing);
                scroll.ScrollTo(scrollOffset);
            });
        }
Beispiel #7
0
 internal ScorePanelTrackingContainer(ScorePanel panel)
 {
     Panel = panel;
     Attach();
 }