public void PreviewToggle()
    {
        _previewing = !_previewing;

        // Disable UI
        foreach (GameObject go in disableDuringPreview)
        {
            go.SetActive(!_previewing);
        }

        // Set chart view mode
        Globals.viewMode = Globals.ViewMode.Chart;

        if (_previewing)
        {
            // Record the current position
            initialPosition = editor.visibleStrikeline.position.y;

            // Move to the start of the chart
            editor.movement.SetTime(-3);

            // Play
            editor.Play();
        }
        else
        {
            // Stop
            editor.Stop();

            // Restore to initial position
            editor.movement.SetTime(ChartEditor.WorldYPositionToTime(initialPosition));
        }
    }
    void Update()
    {
        if (Input.GetMouseButtonDown(2))
        {
            middleClickDownScreenPos = Input.mousePosition;
        }
        else if (!Input.GetMouseButton(2) && middleClickDownScreenPos.HasValue)
        {
            middleClickDownScreenPos = null;
            Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
        }

        if (Input.GetMouseButtonUp(0) && editor.currentState == ChartEditor.State.Editor)
        {
            cancel = false;
        }

        if (Services.IsInDropDown)
        {
            cancel = true;
        }

        // Update timer text
        if (timePosition)
        {
            bool audioLoaded = false;
            foreach (var stream in editor.currentSongAudio.bassAudioStreams)
            {
                if (AudioManager.StreamIsValid(stream))
                {
                    audioLoaded = true;
                }
            }

            if (!audioLoaded)//editor.currentSong.songAudioLoaded)
            {
                timePosition.color = Color.red;
                timePosition.text  = "No audio";
            }
            else
            {
                timePosition.color = Color.white;
                timePosition.text  = Utility.timeConvertion(ChartEditor.WorldYPositionToTime(strikeLine.position.y));
            }
        }

        if (MSChartEditorInput.GetGroupInputDown(arrowKeyShortcutGroup))
        {
            arrowMoveTimer = 0;
        }
        else if (MSChartEditorInput.GetGroupInput(arrowKeyShortcutGroup))
        {
            arrowMoveTimer += Time.deltaTime;
        }
        else
        {
            arrowMoveTimer = 0;
        }
    }
    public void PlayingMovement()
    {
        float   speed          = Globals.gameSettings.hyperspeed;
        Vector3 pos            = transform.position;
        float   deltaTime      = Time.deltaTime;
        float   positionOffset = initPos.y;

        {
            float timeBeforeMovement = ChartEditor.WorldYPositionToTime(pos.y - positionOffset);
            float timeAfterMovement  = timeBeforeMovement + deltaTime * Globals.gameSettings.gameSpeed;

            // Make sure we're staying in sync with the audio
            {
                SongAudioManager songAudioManager = editor.currentSongAudio;

                AudioStream stream = null;

                for (int i = 0; i < EnumX <Song.AudioInstrument> .Count; ++i)
                {
                    Song.AudioInstrument audio = (Song.AudioInstrument)i;
                    if (AudioManager.StreamIsValid(songAudioManager.GetAudioStream(audio)))
                    {
                        stream = songAudioManager.GetAudioStream(audio);
                        break;
                    }
                }

                if (AudioManager.StreamIsValid(stream) && stream.IsPlaying())
                {
                    float audioTimePosition = stream.CurrentPositionInSeconds() - editor.services.totalSongAudioOffset;
                    float desyncAmount      = audioTimePosition - timeAfterMovement;

                    if (Mathf.Abs(desyncAmount) > DESYNCLENIENCE)
                    {
                        timeAfterMovement += desyncAmount;
                    }
                }
            }

            float maxChangeInTimeAllowed = Application.targetFrameRate > 0 ? 2.0f / Application.targetFrameRate : 1.0f / 120.0f;

            float totalChangeInTime = timeAfterMovement - timeBeforeMovement;

            float newTimePosition = ChartEditor.TimeToWorldYPosition(timeBeforeMovement + totalChangeInTime);
            pos.y = newTimePosition + positionOffset;
        }

        selfTransform.position = pos;
        explicitChartPos       = null;

        lastUpdatedRealTime = Time.time;
    }
    public override void OnSelectableMouseDrag()
    {
        // Move object
        if (bpm.tick != 0)
        {
            base.OnSelectableMouseDrag();
        }

        if (draggingInitialBpm != null && MoonscraperEngine.Input.KeyboardDevice.ctrlKeyBeingPressed && Input.GetMouseButton(1))
        {
            BPM previousBpm = SongObjectHelper.GetPreviousNonInclusive(bpm.song.bpms, bpm.tick);
            if (previousBpm != null && previousBpm.anchor == null)
            {
                float desiredWorldPos;
                if (editor.services.mouseMonitorSystem.world2DPosition != null && ((Vector2)editor.services.mouseMonitorSystem.world2DPosition).y < editor.mouseYMaxLimit.position.y)
                {
                    desiredWorldPos = ((Vector2)editor.services.mouseMonitorSystem.world2DPosition).y;
                }
                else
                {
                    desiredWorldPos = editor.mouseYMaxLimit.position.y;
                }

                float desiredTime = ChartEditor.WorldYPositionToTime(desiredWorldPos);
                if (desiredTime < previousBpm.time)
                {
                    desiredTime = previousBpm.time;
                }

                BPM nextBpm = SongObjectHelper.GetNextNonInclusive(bpm.song.bpms, bpm.tick);
                if (nextBpm != null && nextBpm.anchor != null && desiredTime >= nextBpm.time)
                {
                    desiredTime = nextBpm.time - 0.01f;
                }

                double disToBpm    = TickFunctions.DisToBpm(previousBpm.tick, bpm.tick, desiredTime - previousBpm.time, bpm.song.resolution);
                uint   newBpmValue = (uint)Mathf.Ceil((float)disToBpm * 1000.0f);
                if (newBpmValue > 0)
                {
                    if (hasPushed)
                    {
                        editor.commandStack.Pop();
                    }

                    editor.commandStack.Push(new SongEditModify <BPM>(previousBpm, new BPM(previousBpm.tick, newBpmValue, previousBpm.anchor)));
                    hasPushed = true;
                }
            }
        }
    }
 public static uint WorldYPositionToTick(this Song song, float worldYPos, float resolution)
 {
     return(song.TimeToTick(ChartEditor.WorldYPositionToTime(worldYPos), resolution));
 }