public override void Load() { base.Load(); refreshAudio(); WidgetManager.Root.Add(mainStoryboardContainer = new DrawableContainer(WidgetManager) { Drawable = mainStoryboardDrawable = new StoryboardDrawable(project) { UpdateFrameStats = true, }, AnchorTarget = WidgetManager.Root, AnchorFrom = BoxAlignment.Centre, AnchorTo = BoxAlignment.Centre, }); WidgetManager.Root.Add(bottomLeftLayout = new LinearLayout(WidgetManager) { AnchorTarget = WidgetManager.Root, AnchorFrom = BoxAlignment.BottomLeft, AnchorTo = BoxAlignment.BottomLeft, Padding = new FourSide(16, 8, 16, 16), Horizontal = true, Fill = true, Children = new Widget[] { timeButton = new Button(WidgetManager) { StyleName = "small", AnchorFrom = BoxAlignment.Centre, Text = "--:--:---", Tooltip = "Current time\nCtrl-C to copy", CanGrow = false, }, divisorButton = new Button(WidgetManager) { StyleName = "small", Text = $"1/{snapDivisor}", Tooltip = "Snap divisor", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, audioTimeFactorButton = new Button(WidgetManager) { StyleName = "small", Text = $"{timeSource.TimeFactor:P0}", Tooltip = "Audio speed", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, timeline = new TimelineSlider(WidgetManager, project) { AnchorFrom = BoxAlignment.Centre, SnapDivisor = snapDivisor, }, changeMapButton = new Button(WidgetManager) { StyleName = "icon", Icon = IconFont.FilesO, Tooltip = "Change beatmap", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, fitButton = new Button(WidgetManager) { StyleName = "icon", Icon = IconFont.Desktop, Tooltip = "Fit/Fill", AnchorFrom = BoxAlignment.Centre, CanGrow = false, Checkable = true, }, playPauseButton = new Button(WidgetManager) { StyleName = "icon", Icon = IconFont.Play, Tooltip = "Play/Pause\nShortcut: Space", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, }, }); WidgetManager.Root.Add(bottomRightLayout = new LinearLayout(WidgetManager) { AnchorTarget = WidgetManager.Root, AnchorFrom = BoxAlignment.BottomRight, AnchorTo = BoxAlignment.BottomRight, Padding = new FourSide(16, 16, 16, 8), Horizontal = true, Fill = true, Children = new Widget[] { effectsButton = new Button(WidgetManager) { StyleName = "small", Text = "Effects", }, layersButton = new Button(WidgetManager) { StyleName = "small", Text = "Layers", }, settingsButton = new Button(WidgetManager) { StyleName = "small", Text = "Settings", }, projectFolderButton = new Button(WidgetManager) { StyleName = "icon", Icon = IconFont.FolderOpen, Tooltip = "Open project folder", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, mapsetFolderButton = new Button(WidgetManager) { StyleName = "icon", Icon = IconFont.FolderOpen, Tooltip = "Open mapset folder\n(Right click to change)", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, saveButton = new Button(WidgetManager) { StyleName = "icon", Icon = IconFont.Save, Tooltip = "Save project\nShortcut: Ctrl-S", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, exportButton = new Button(WidgetManager) { StyleName = "icon", Icon = IconFont.PuzzlePiece, Tooltip = "Export to .osb\n(Right click to export once for each diff)", AnchorFrom = BoxAlignment.Centre, CanGrow = false, }, }, }); WidgetManager.Root.Add(effectConfigUi = new EffectConfigUi(WidgetManager) { AnchorTarget = WidgetManager.Root, AnchorFrom = BoxAlignment.TopLeft, AnchorTo = BoxAlignment.TopLeft, Offset = new Vector2(16, 16), Displayed = false, }); effectConfigUi.OnDisplayedChanged += (sender, e) => resizeStoryboard(); WidgetManager.Root.Add(effectsList = new EffectList(WidgetManager, project, effectConfigUi) { AnchorTarget = bottomRightLayout, AnchorFrom = BoxAlignment.BottomRight, AnchorTo = BoxAlignment.TopRight, Offset = new Vector2(-16, 0), }); effectsList.OnEffectPreselect += effect => { if (effect != null) { timeline.Highlight(effect.StartTime, effect.EndTime); } else { timeline.ClearHighlight(); } }; effectsList.OnEffectSelected += effect => timeline.Value = (float)effect.StartTime / 1000; WidgetManager.Root.Add(layersList = new LayerList(WidgetManager, project.LayerManager) { AnchorTarget = bottomRightLayout, AnchorFrom = BoxAlignment.BottomRight, AnchorTo = BoxAlignment.TopRight, Offset = new Vector2(-16, 0), }); layersList.OnLayerPreselect += layer => { if (layer != null) { timeline.Highlight(layer.StartTime, layer.EndTime); } else { timeline.ClearHighlight(); } }; layersList.OnLayerSelected += layer => timeline.Value = (float)layer.StartTime / 1000; WidgetManager.Root.Add(settingsMenu = new SettingsMenu(WidgetManager, project) { AnchorTarget = bottomRightLayout, AnchorFrom = BoxAlignment.BottomRight, AnchorTo = BoxAlignment.TopRight, Offset = new Vector2(-16, 0), }); WidgetManager.Root.Add(statusLayout = new LinearLayout(WidgetManager) { StyleName = "tooltip", AnchorTarget = bottomLeftLayout, AnchorFrom = BoxAlignment.BottomLeft, AnchorTo = BoxAlignment.TopLeft, Offset = new Vector2(16, 0), Horizontal = true, Hoverable = false, Displayed = false, Children = new Widget[] { statusIcon = new Label(WidgetManager) { StyleName = "icon", AnchorFrom = BoxAlignment.Left, CanGrow = false, }, statusMessage = new Label(WidgetManager) { AnchorFrom = BoxAlignment.Left, }, }, }); WidgetManager.Root.Add(warningsLabel = new Label(WidgetManager) { StyleName = "tooltip", AnchorTarget = timeline, AnchorFrom = BoxAlignment.BottomLeft, AnchorTo = BoxAlignment.TopLeft, Offset = new Vector2(0, -8), }); WidgetManager.Root.Add(previewContainer = new DrawableContainer(WidgetManager) { StyleName = "storyboardPreview", Drawable = previewDrawable = new StoryboardDrawable(project), AnchorTarget = timeline, AnchorFrom = BoxAlignment.Bottom, AnchorTo = BoxAlignment.Top, Hoverable = false, Displayed = false, Size = new Vector2(16, 9) * 16, }); timeButton.OnClick += (sender, e) => Manager.ShowPrompt("Skip to...", value => { if (float.TryParse(value, out float time)) { timeline.Value = time / 1000; } }); resizeTimeline(); timeline.OnValueChanged += (sender, e) => pendingSeek = timeline.Value; timeline.OnValueCommited += (sender, e) => timeline.Snap(); timeline.OnHovered += (sender, e) => previewContainer.Displayed = e.Hovered; changeMapButton.OnClick += (sender, e) => { if (project.MapsetManager.BeatmapCount > 2) { Manager.ShowContextMenu("Select a beatmap", beatmap => project.SelectBeatmap(beatmap.Id, beatmap.Name), project.MapsetManager.Beatmaps); } else { project.SwitchMainBeatmap(); } }; Program.Settings.FitStoryboard.Bind(fitButton, () => resizeStoryboard()); playPauseButton.OnClick += (sender, e) => timeSource.Playing = !timeSource.Playing; divisorButton.OnClick += (sender, e) => { snapDivisor++; if (snapDivisor == 5 || snapDivisor == 7) { snapDivisor++; } if (snapDivisor == 9) { snapDivisor = 12; } if (snapDivisor == 13) { snapDivisor = 16; } if (snapDivisor > 16) { snapDivisor = 1; } timeline.SnapDivisor = snapDivisor; divisorButton.Text = $"1/{snapDivisor}"; }; audioTimeFactorButton.OnClick += (sender, e) => { if (e == MouseButton.Left) { var speed = timeSource.TimeFactor; if (speed > 1) { speed = 2; } speed *= 0.5; if (speed < 0.2) { speed = 1; } timeSource.TimeFactor = speed; } else if (e == MouseButton.Right) { var speed = timeSource.TimeFactor; if (speed < 1) { speed = 1; } speed += speed >= 2 ? 1 : 0.5; if (speed > 8) { speed = 1; } timeSource.TimeFactor = speed; } else if (e == MouseButton.Middle) { timeSource.TimeFactor = timeSource.TimeFactor == 8 ? 1 : 8; } audioTimeFactorButton.Text = $"{timeSource.TimeFactor:P0}"; }; MakeTabs( new Button[] { settingsButton, effectsButton, layersButton }, new Widget[] { settingsMenu, effectsList, layersList }); projectFolderButton.OnClick += (sender, e) => { var path = Path.GetFullPath(project.ProjectFolderPath); if (Directory.Exists(path)) { Process.Start(path); } }; mapsetFolderButton.OnClick += (sender, e) => { var path = Path.GetFullPath(project.MapsetPath); if (e == MouseButton.Right || !Directory.Exists(path)) { changeMapsetFolder(); } else { Process.Start(path); } }; saveButton.OnClick += (sender, e) => saveProject(); exportButton.OnClick += (sender, e) => { if (e == MouseButton.Right) { exportProjectAll(); } else { exportProject(); } }; project.OnMapsetPathChanged += project_OnMapsetPathChanged; project.OnEffectsContentChanged += project_OnEffectsContentChanged; project.OnEffectsStatusChanged += project_OnEffectsStatusChanged; if (!project.MapsetPathIsValid) { Manager.ShowMessage($"The mapset folder cannot be found.\n{project.MapsetPath}\n\nPlease select a new one.", () => changeMapsetFolder(), true); } }