/// <summary> /// Adds a HitObject sprite to the container. /// </summary> public void AddHitObjectSprite(HitObjectInfo h) { DrawableEditorHitObject hitObject; var skin = SkinManager.Skin.Keys[Ruleset.WorkingMap.Mode]; var index = skin.ColorObjectsBySnapDistance ? HitObjectManager.GetBeatSnap(h, h.GetTimingPoint(Ruleset.WorkingMap.TimingPoints)) : 0; if (h.IsLongNote) { if (ConfigManager.EditorViewLayers.Value) { hitObject = new DrawableEditorHitObjectLong(this, h, skin.EditorLayerNoteHitObjects[h.Lane - 1], skin.EditorLayerNoteHoldBodies[h.Lane - 1], skin.EditorLayerNoteHoldEnds[h.Lane - 1]); } else { hitObject = new DrawableEditorHitObjectLong(this, h, skin.NoteHoldHitObjects[h.Lane - 1][index], skin.NoteHoldBodies[h.Lane - 1].First(), skin.NoteHoldEnds[h.Lane - 1]); } } else { if (ConfigManager.EditorViewLayers.Value) { hitObject = new DrawableEditorHitObject(this, h, skin.EditorLayerNoteHitObjects[h.Lane - 1]); } else { hitObject = new DrawableEditorHitObject(this, h, skin.NoteHitObjects[h.Lane - 1][index]); } } hitObject.Alignment = Alignment.TopLeft; hitObject.X = ScreenRectangle.X + LaneSize * (h.Lane - 1) + DividerLineWidth; hitObject.Width = LaneSize - DividerLineWidth; // Make sure the width of the long note is updated if this object is indeed an LN. if (hitObject is DrawableEditorHitObjectLong longNote) { longNote.Body.Width = hitObject.Width; longNote.Tail.Width = hitObject.Width; } hitObject.AppearAsActive(); // Check if the layer is hidden that the user is adding the object to and display the object // as that appropriate colour. if (((EditorScreenView)Ruleset.Screen.View).LayerCompositor.ScrollContainer.AvailableItems[hitObject.Info.EditorLayer].Hidden) { hitObject.AppearAsHiddenInLayer(); } lock (HitObjects) HitObjects.Add(hitObject); }
/// <summary> /// Deselects an individual HitObject /// </summary> /// <param name="h"></param> public void DeselectHitObject(DrawableEditorHitObject h) { var layer = View.LayerCompositor.ScrollContainer.AvailableItems[h.Info.EditorLayer]; if (PendingLongNoteReleases.Contains(h.Info)) { var ln = h as DrawableEditorHitObjectLong; ln?.AppearAsInactive(); } if (layer.Hidden) { h.AppearAsHiddenInLayer(); } else { h.AppearAsActive(); } SelectedHitObjects.Remove(h); SetSelectedHitsounds(); }
/// <summary> /// Selects an individual HitObject /// </summary> /// <param name="h"></param> public void SelectHitObject(DrawableEditorHitObject h) { h.AppearAsSelected(); SelectedHitObjects.Add(h); SetSelectedHitsounds(); }
/// <summary> /// Places a HitObject at a given lane. /// </summary> /// <param name="inputDevice"></param> /// <param name="lane"></param> /// <param name="time"></param> private void PlaceObject(CompositionInputDevice inputDevice, int lane, double time) { var am = ActionManager as EditorActionManagerKeys; if (HandlePendingLongNoteReleases(lane, time)) { return; } // Find an existing object in the current lane at the same time, so we can determine if // the object should be placed or deleted accordingly. HitObjectInfo existingObject = null; DrawableEditorHitObject hoveredObject = null; switch (inputDevice) { case CompositionInputDevice.Keyboard: existingObject = WorkingMap.HitObjects.Find(x => x.StartTime == (int)time && x.Lane == lane); break; case CompositionInputDevice.Mouse: hoveredObject = ScrollContainer.GetHoveredHitObject(); if (hoveredObject != null) { existingObject = hoveredObject.Info; } break; default: throw new ArgumentOutOfRangeException(nameof(inputDevice), inputDevice, null); } // There's no object currently at this position, so add it. if (existingObject == null) { switch (CompositionTool.Value) { case EditorCompositionTool.Note: am?.PlaceHitObject(lane, time); break; case EditorCompositionTool.LongNote: am?.PlaceLongNote(lane, time); // Makes sure the long note is marked as pending, so any future objects placed in this lane // will be awarded to this LN's end. var workingObject = WorkingMap.HitObjects.Find(x => x.StartTime == (int)time && x.Lane == lane); PendingLongNoteReleases[lane - 1] = workingObject; // Make the long note appear as inactive/dead. Gives a visual effect to the user that // they need to do something with the note. if (!(ScrollContainer.HitObjects.Find(x => x.Info == workingObject) is DrawableEditorHitObjectLong drawable)) { return; } drawable.AppearAsInactive(); if (!GaveLongNoteGuide) { NotificationManager.Show(NotificationLevel.Info, "Scroll through the timeline and place the end of the long note."); GaveLongNoteGuide = true; } break; default: NotificationManager.Show(NotificationLevel.Error, "This tool isn't implemented yet. Choose another!"); break; } } // An object exists, so delete it. else { switch (inputDevice) { case CompositionInputDevice.Keyboard: am?.DeleteHitObject(existingObject); break; case CompositionInputDevice.Mouse: // hoveredObject?.AppearAsSelected(); break; default: throw new ArgumentOutOfRangeException(nameof(inputDevice), inputDevice, null); } } }