├── .gitattributes ├── .gitignore ├── CONTRIBUTING.md ├── Ched.Core ├── BarIndexCalculator.cs ├── Ched.Core.csproj ├── Ched.Core.nuspec ├── Constants.cs ├── EventCollection.cs ├── Events │ ├── BpmChangeEvent.cs │ ├── EventBase.cs │ ├── HighSpeedChangeEvent.cs │ ├── InvalidTimeSignatureException.cs │ └── TimeSignatureChangeEvent.cs ├── NoteCollection.cs ├── Notes │ ├── Air.cs │ ├── AirAction.cs │ ├── Damage.cs │ ├── ExTap.cs │ ├── Flick.cs │ ├── Hold.cs │ ├── LongNoteBase.cs │ ├── Slide.cs │ ├── Tap.cs │ └── TappableBase.cs ├── Properties │ └── AssemblyInfo.cs ├── Score.cs ├── ScoreBook.cs ├── TimeCalculator.cs ├── UI │ └── SelectionRange.cs └── packages.config ├── Ched.Drawing ├── Ched.Drawing.csproj ├── Ched.Drawing.nuspec ├── ColorProfile.cs ├── ComponentGraphics.cs ├── DrawingContext.cs ├── GraphicsExtensions.cs ├── NoteGraphics.cs └── Properties │ └── AssemblyInfo.cs ├── Ched.Plugins ├── Ched.Plugins.csproj ├── Ched.Plugins.nuspec ├── Diagnostics.cs ├── IPlugin.cs ├── IScoreBookExportPlugin.cs ├── IScoreBookImportPlugin.cs ├── IScorePlugin.cs ├── Properties │ └── AssemblyInfo.cs └── UserCancelledException.cs ├── Ched.sln ├── Ched ├── App.config ├── Ched.csproj ├── Components │ └── Exporter │ │ └── SusExporter.cs ├── Configuration │ ├── ApplicationSettings.cs │ ├── SettingsBase.cs │ └── SoundSettings.cs ├── Localization │ ├── ErrorStrings.Designer.cs │ ├── ErrorStrings.en.resx │ ├── ErrorStrings.resx │ ├── FileFilterStrings.Designer.cs │ ├── FileFilterStrings.en.resx │ ├── FileFilterStrings.resx │ ├── MainFormStrings.Designer.cs │ ├── MainFormStrings.en.Designer.cs │ ├── MainFormStrings.en.resx │ ├── MainFormStrings.resx │ ├── PluginStrings.Designer.cs │ ├── PluginStrings.en.Designer.cs │ ├── PluginStrings.en.resx │ └── PluginStrings.resx ├── Plugins │ ├── ComboCalculator.cs │ ├── ExportManager.cs │ ├── PluginManager.cs │ ├── ScoreBookExportPluginArgs.cs │ ├── ScoreBookImportPluginArgs.cs │ ├── ScorePluginArgs.cs │ ├── ShiftEvent.cs │ ├── SlideKnitter.cs │ ├── SlideMerger.cs │ ├── SlideReverser.cs │ ├── SlideSplitter.cs │ └── SusExportPlugin.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ ├── airaction.png │ ├── airdown.png │ ├── airleftdown.png │ ├── airleftup.png │ ├── airrightdown.png │ ├── airrightup.png │ ├── airup.png │ ├── arrow-curve-180-left.png │ ├── arrow-curve.png │ ├── blue-document-export.png │ ├── clipboard-paste.png │ ├── cross-circle.png │ ├── damage.png │ ├── disk-black.png │ ├── document--plus.png │ ├── document-copy.png │ ├── eraser.png │ ├── exclamation.png │ ├── extap.png │ ├── flick.png │ ├── folder-horizontal-open.png │ ├── guide.mp3 │ ├── hold.png │ ├── icon.ico │ ├── information.png │ ├── magnifier-zoom-in.png │ ├── magnifier-zoom-out.png │ ├── pencil.png │ ├── scissors-blue.png │ ├── selection.png │ ├── slide.png │ ├── slidestep.png │ └── tap.png ├── UI │ ├── BpmSelectionForm.Designer.cs │ ├── BpmSelectionForm.cs │ ├── BpmSelectionForm.en.resx │ ├── BpmSelectionForm.resx │ ├── CheckableToolStripSplitButton.cs │ ├── ControlExtensions.cs │ ├── CustomQuantizeSelectionForm.Designer.cs │ ├── CustomQuantizeSelectionForm.cs │ ├── CustomQuantizeSelectionForm.en.resx │ ├── CustomQuantizeSelectionForm.resx │ ├── GraphicsExtensions.cs │ ├── Helpers.cs │ ├── HighSpeedSelectionForm.Designer.cs │ ├── HighSpeedSelectionForm.cs │ ├── HighSpeedSelectionForm.en.resx │ ├── HighSpeedSelectionForm.resx │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ ├── MainForm.resx │ ├── NoteView.Designer.cs │ ├── NoteView.cs │ ├── Operations │ │ ├── CompositeOperation.cs │ │ ├── EditNoteOperation.cs │ │ ├── EventCollectionOperation.cs │ │ ├── IOperation.cs │ │ ├── NoteCollectionOperation.cs │ │ ├── OperationManager.cs │ │ └── ScoreOperation.cs │ ├── PlaneExtensions.cs │ ├── ShiftTimeSelectionForm.Designer.cs │ ├── ShiftTimeSelectionForm.cs │ ├── ShiftTimeSelectionForm.resx │ ├── Shortcuts │ │ ├── Commands.cs │ │ ├── KeyExtensions.cs │ │ ├── ShortcutCommandSource.cs │ │ ├── ShortcutKeySource.cs │ │ ├── ShortcutManager.cs │ │ └── ToolStripItemBuilder.cs │ ├── SoundManager.cs │ ├── SoundPreviewManager.cs │ ├── TimeSignatureSelectionForm.Designer.cs │ ├── TimeSignatureSelectionForm.cs │ ├── TimeSignatureSelectionForm.en.resx │ ├── TimeSignatureSelectionForm.resx │ ├── VersionInfoForm.Designer.cs │ ├── VersionInfoForm.cs │ ├── VersionInfoForm.en.resx │ ├── VersionInfoForm.resx │ └── Windows │ │ ├── Behaviors │ │ ├── HideWindowCloseButtonBehavior.cs │ │ ├── InitialFocusBehavior.cs │ │ ├── OpenFileBehavior.cs │ │ ├── StyleBehaviorCollection.cs │ │ └── UpdateOnEnterPressBehaviors.cs │ │ ├── BindableNumericUpDown.xaml │ │ ├── BindableNumericUpDown.xaml.cs │ │ ├── BookPropertiesWindow.xaml │ │ ├── BookPropertiesWindow.xaml.cs │ │ ├── CommonStyles.xaml │ │ ├── Converters │ │ ├── BitmapImageSourceConverter.cs │ │ ├── ShortcutKeyTextConverter.cs │ │ └── VolumeConverter.cs │ │ ├── DiagnosticsWindow.xaml │ │ ├── DiagnosticsWindow.xaml.cs │ │ ├── EnumSourceProvider.cs │ │ ├── ShortcutSettingsWindow.xaml │ │ ├── ShortcutSettingsWindow.xaml.cs │ │ ├── SusExportWindow.xaml │ │ ├── SusExportWindow.xaml.cs │ │ ├── ViewModel.cs │ │ └── WpfExtensions.cs └── packages.config ├── LICENSE ├── README.md └── appveyor.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to Ched 2 | 3 | ## Did you find a bug? 4 | 5 | * Open a new GitHub issue with a clear title, steps to reproduce the bug, executable version, and other environment information. 6 | * Ensure the bug was not already reported by searching existing issues. 7 | 8 | ## Did you write a patch that fixes a bug? 9 | 10 | * Open a new GitHub pull request with the changes. 11 | * Ensure the branch for the pull request is based on the **latest develop branch** at that time. 12 | -------------------------------------------------------------------------------- /Ched.Core/Ched.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5A5FF947-79DC-4352-94D5-EEC14065F93A} 8 | Library 9 | Properties 10 | Ched.Core 11 | Ched.Core 12 | v4.8 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | true 35 | bin\x86\Debug\ 36 | DEBUG;TRACE 37 | full 38 | x86 39 | prompt 40 | MinimumRecommendedRules.ruleset 41 | 42 | 43 | bin\x86\Release\ 44 | TRACE 45 | true 46 | pdbonly 47 | x86 48 | prompt 49 | MinimumRecommendedRules.ruleset 50 | 51 | 52 | 53 | ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll 54 | True 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 103 | -------------------------------------------------------------------------------- /Ched.Core/Ched.Core.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $id$ 5 | $version$ 6 | $description$ 7 | $author$ 8 | 9 | https://github.com/paralleltree/Ched 10 | MIT 11 | false 12 | 13 | 14 | -------------------------------------------------------------------------------- /Ched.Core/Constants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core 8 | { 9 | public static class Constants 10 | { 11 | public static int LanesCount = 16; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Ched.Core/EventCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core.Events; 8 | 9 | namespace Ched.Core 10 | { 11 | /// 12 | /// イベントを格納するコレクションを表すクラスです。 13 | /// 14 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 15 | public class EventCollection 16 | { 17 | [Newtonsoft.Json.JsonProperty] 18 | private List bpmChangeEvents = new List(); 19 | [Newtonsoft.Json.JsonProperty] 20 | private List timeSignatureChangeEvents = new List(); 21 | [Newtonsoft.Json.JsonProperty] 22 | private List highSpeedChangeEvents = new List(); 23 | 24 | public List BpmChangeEvents 25 | { 26 | get { return bpmChangeEvents; } 27 | set { bpmChangeEvents = value; } 28 | } 29 | 30 | public List TimeSignatureChangeEvents 31 | { 32 | get { return timeSignatureChangeEvents; } 33 | set { timeSignatureChangeEvents = value; } 34 | } 35 | 36 | public List HighSpeedChangeEvents 37 | { 38 | get { return highSpeedChangeEvents; } 39 | set { highSpeedChangeEvents = value; } 40 | } 41 | 42 | public IEnumerable AllEvents => 43 | BpmChangeEvents.Cast() 44 | .Concat(TimeSignatureChangeEvents) 45 | .Concat(HighSpeedChangeEvents); 46 | 47 | public void UpdateTicksPerBeat(double factor) 48 | { 49 | var events = BpmChangeEvents.Cast() 50 | .Concat(TimeSignatureChangeEvents) 51 | .Concat(HighSpeedChangeEvents); 52 | foreach (var e in events) 53 | e.Tick = (int)(e.Tick * factor); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Ched.Core/Events/BpmChangeEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Core.Events 9 | { 10 | /// 11 | /// BPMの変更イベントを表すクラスです。 12 | /// 13 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 14 | [DebuggerDisplay("Tick = {Tick}, Value = {Bpm}")] 15 | public class BpmChangeEvent : EventBase 16 | { 17 | [Newtonsoft.Json.JsonProperty] 18 | private double bpm; 19 | 20 | public double Bpm 21 | { 22 | get { return bpm; } 23 | set { bpm = value; } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Ched.Core/Events/EventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Core.Events 9 | { 10 | /// 11 | /// 譜面におけるイベントを表すクラスです。 12 | /// 13 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 14 | [DebuggerDisplay("Tick = {Tick}")] 15 | public abstract class EventBase 16 | { 17 | [Newtonsoft.Json.JsonProperty] 18 | private int tick; 19 | 20 | /// 21 | /// このイベントの位置を表すTick値を取得、設定します。 22 | /// 23 | public int Tick 24 | { 25 | get { return tick; } 26 | set 27 | { 28 | if (value < 0) throw new ArgumentOutOfRangeException("value", "Tick must be greater than or equal to 0."); 29 | tick = value; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Ched.Core/Events/HighSpeedChangeEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Core.Events 9 | { 10 | /// 11 | /// ハイスピードの変更を表すクラスです。 12 | /// 13 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 14 | [DebuggerDisplay("Tick = {Tick}, Value = {SpeedRatio}")] 15 | public class HighSpeedChangeEvent : EventBase 16 | { 17 | [Newtonsoft.Json.JsonProperty] 18 | private decimal speedRatio; 19 | 20 | /// 21 | /// 1を基準とする速度比を設定します。 22 | /// 23 | public decimal SpeedRatio 24 | { 25 | get { return speedRatio; } 26 | set { speedRatio = value; } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Ched.Core/Events/InvalidTimeSignatureException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Core.Events 9 | { 10 | /// 11 | /// 拍子定義が無効な場合にスローされる例外です。 12 | /// 13 | [Serializable] 14 | public class InvalidTimeSignatureException : Exception 15 | { 16 | private static readonly string TickPropertyValue = "tick"; 17 | 18 | /// 19 | /// 無効な拍子定義の位置を表すTick値を取得します。 20 | /// 21 | public int Tick { get; } 22 | 23 | public InvalidTimeSignatureException() : base() 24 | { 25 | } 26 | 27 | public InvalidTimeSignatureException(string message) : base(message) 28 | { 29 | } 30 | 31 | public InvalidTimeSignatureException(string message, Exception inner) : base(message, inner) 32 | { 33 | } 34 | 35 | public InvalidTimeSignatureException(string message, int tick) : this(message, tick, null) 36 | { 37 | } 38 | 39 | public InvalidTimeSignatureException(string message, int tick, Exception innerException) : base(message, innerException) 40 | { 41 | Tick = tick; 42 | } 43 | 44 | protected InvalidTimeSignatureException(SerializationInfo info, StreamingContext context) : base(info, context) 45 | { 46 | if (info == null) return; 47 | Tick = info.GetInt32(TickPropertyValue); 48 | } 49 | 50 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 51 | { 52 | base.GetObjectData(info, context); 53 | if (info == null) return; 54 | 55 | info.AddValue(TickPropertyValue, Tick); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Ched.Core/Events/TimeSignatureChangeEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Core.Events 9 | { 10 | /// 11 | /// 拍子の変更を表します。 12 | /// 13 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 14 | [DebuggerDisplay("Tick = {Tick}, Value = {Numerator} / {Denominator}")] 15 | public class TimeSignatureChangeEvent : EventBase 16 | { 17 | [Newtonsoft.Json.JsonProperty] 18 | private int numerator; 19 | [Newtonsoft.Json.JsonProperty] 20 | private int denominatorExponent; 21 | 22 | /// 23 | /// 拍子の分子を設定します。 24 | /// 25 | public int Numerator 26 | { 27 | get { return numerator; } 28 | set 29 | { 30 | if (value < 1) throw new ArgumentOutOfRangeException("value must be greater than 0."); 31 | numerator = value; 32 | } 33 | } 34 | 35 | /// 36 | /// 拍子の分母を取得します。 37 | /// 38 | public int Denominator 39 | { 40 | get 41 | { 42 | int p = 1; 43 | for (int i = 0; i < DenominatorExponent; i++) p *= 2; 44 | return p; 45 | } 46 | } 47 | 48 | /// 49 | /// 2を底とする拍子の分母の指数を設定します。 50 | /// 51 | public int DenominatorExponent 52 | { 53 | get { return denominatorExponent; } 54 | set 55 | { 56 | if (value < 0) throw new ArgumentOutOfRangeException("value must be positive."); 57 | denominatorExponent = value; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Ched.Core/NoteCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core.Notes; 8 | 9 | namespace Ched.Core 10 | { 11 | /// 12 | /// ノーツを格納するコレクションを表すクラスです。 13 | /// 14 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 15 | public class NoteCollection 16 | { 17 | [Newtonsoft.Json.JsonProperty] 18 | private List taps; 19 | [Newtonsoft.Json.JsonProperty] 20 | private List exTaps; 21 | [Newtonsoft.Json.JsonProperty] 22 | private List holds; 23 | [Newtonsoft.Json.JsonProperty] 24 | private List slides; 25 | [Newtonsoft.Json.JsonProperty] 26 | private List flicks; 27 | [Newtonsoft.Json.JsonProperty] 28 | private List damages; 29 | [Newtonsoft.Json.JsonProperty] 30 | private List airs; 31 | [Newtonsoft.Json.JsonProperty] 32 | private List airActions; 33 | 34 | public List Taps 35 | { 36 | get { return taps; } 37 | set { taps = value; } 38 | } 39 | 40 | public List ExTaps 41 | { 42 | get { return exTaps; } 43 | set { exTaps = value; } 44 | } 45 | 46 | public List Holds 47 | { 48 | get { return holds; } 49 | set { holds = value; } 50 | } 51 | 52 | public List Slides 53 | { 54 | get { return slides; } 55 | set { slides = value; } 56 | } 57 | 58 | public List Airs 59 | { 60 | get { return airs; } 61 | set { airs = value; } 62 | } 63 | 64 | public List AirActions 65 | { 66 | get { return airActions; } 67 | set { airActions = value; } 68 | } 69 | 70 | public List Flicks 71 | { 72 | get { return flicks; } 73 | set { flicks = value; } 74 | } 75 | 76 | public List Damages 77 | { 78 | get { return damages; } 79 | set { damages = value; } 80 | } 81 | 82 | public NoteCollection() 83 | { 84 | Taps = new List(); 85 | ExTaps = new List(); 86 | Holds = new List(); 87 | Slides = new List(); 88 | Airs = new List(); 89 | AirActions = new List(); 90 | Flicks = new List(); 91 | Damages = new List(); 92 | } 93 | 94 | public NoteCollection(NoteCollection collection) 95 | { 96 | Taps = collection.Taps.ToList(); 97 | ExTaps = collection.ExTaps.ToList(); 98 | Holds = collection.Holds.ToList(); 99 | Slides = collection.Slides.ToList(); 100 | Airs = collection.Airs.ToList(); 101 | AirActions = collection.AirActions.ToList(); 102 | Flicks = collection.Flicks.ToList(); 103 | Damages = collection.Damages.ToList(); 104 | } 105 | 106 | public IEnumerable GetShortNotes() 107 | { 108 | return Taps.Cast().Concat(ExTaps).Concat(Flicks).Concat(Damages); 109 | } 110 | 111 | public void UpdateTicksPerBeat(double factor) 112 | { 113 | foreach (var note in GetShortNotes()) 114 | note.Tick = (int)(note.Tick * factor); 115 | 116 | foreach (var hold in Holds) 117 | { 118 | hold.StartTick = (int)(hold.StartTick * factor); 119 | hold.Duration = (int)(hold.Duration * factor); 120 | } 121 | 122 | foreach (var slide in Slides) 123 | { 124 | slide.StartTick = (int)(slide.StartTick * factor); 125 | foreach (var step in slide.StepNotes) 126 | step.TickOffset = (int)(step.TickOffset * factor); 127 | } 128 | 129 | foreach (var action in AirActions.SelectMany(p => p.ActionNotes)) 130 | action.Offset = (int)(action.Offset * factor); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Ched.Core/Notes/Air.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 10 | public class Air 11 | { 12 | [Newtonsoft.Json.JsonProperty] 13 | private IAirable parentNote; 14 | [Newtonsoft.Json.JsonProperty] 15 | private VerticalAirDirection verticalDirection; 16 | [Newtonsoft.Json.JsonProperty] 17 | private HorizontalAirDirection horizontalDirection; 18 | 19 | public IAirable ParentNote { get { return parentNote; } } 20 | 21 | public VerticalAirDirection VerticalDirection 22 | { 23 | get { return verticalDirection; } 24 | set { verticalDirection = value; } 25 | } 26 | 27 | public HorizontalAirDirection HorizontalDirection 28 | { 29 | get { return horizontalDirection; } 30 | set { horizontalDirection = value; } 31 | } 32 | 33 | public int Tick { get { return ParentNote.Tick; } } 34 | 35 | public int LaneIndex { get { return ParentNote.LaneIndex; } } 36 | 37 | public int Width { get { return ParentNote.Width; } } 38 | 39 | public Air(IAirable parent) 40 | { 41 | parentNote = parent; 42 | } 43 | 44 | public void Flip() 45 | { 46 | if (HorizontalDirection == HorizontalAirDirection.Center) return; 47 | HorizontalDirection = HorizontalDirection == HorizontalAirDirection.Left ? HorizontalAirDirection.Right : HorizontalAirDirection.Left; 48 | } 49 | } 50 | 51 | public interface IAirable 52 | { 53 | /// 54 | /// ノートの位置を表すTickを設定します。 55 | /// 56 | int Tick { get; } 57 | 58 | /// 59 | /// ノートの配置されるレーン番号を取得します。。 60 | /// 61 | int LaneIndex { get; } 62 | 63 | /// 64 | /// ノートのレーン幅を取得します。 65 | /// 66 | int Width { get; } 67 | } 68 | 69 | public enum VerticalAirDirection 70 | { 71 | Up, 72 | Down 73 | } 74 | 75 | public enum HorizontalAirDirection 76 | { 77 | Center, 78 | Left, 79 | Right 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Ched.Core/Notes/AirAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 10 | public class AirAction : ILongNote 11 | { 12 | [Newtonsoft.Json.JsonProperty] 13 | private IAirable parentNote; 14 | [Newtonsoft.Json.JsonProperty] 15 | private List actionNotes = new List(); 16 | 17 | public List ActionNotes { get { return actionNotes; } } 18 | public IAirable ParentNote { get { return parentNote; } } 19 | public int StartTick => ParentNote.Tick; 20 | 21 | /// 22 | /// 親オブジェクトを持たないの新しいインスタンスを初期化します。 23 | /// 24 | /// このコンストラクタはシリアライザ用に存在します。 25 | public AirAction() 26 | { 27 | } 28 | 29 | /// 30 | /// 指定のを親とするの新しいインスタンスを初期化します。 31 | /// 32 | /// このの親となるオブジェクト 33 | public AirAction(IAirable parent) 34 | { 35 | parentNote = parent; 36 | } 37 | 38 | public int GetDuration() 39 | { 40 | return ActionNotes.Max(p => p.Offset); 41 | } 42 | 43 | 44 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 45 | public class ActionNote 46 | { 47 | [Newtonsoft.Json.JsonProperty] 48 | private int offset; 49 | [Newtonsoft.Json.JsonProperty] 50 | private AirAction parentNote; 51 | 52 | public AirAction ParentNote { get { return parentNote; } } 53 | 54 | public int Offset 55 | { 56 | get { return offset; } 57 | set 58 | { 59 | if (value <= 0) throw new ArgumentOutOfRangeException("value", "value must be positive."); 60 | offset = value; 61 | } 62 | } 63 | 64 | /// 65 | /// 指定のを親とするの新しいインスタンスを初期化します。 66 | /// 67 | /// このの親となるオブジェクト 68 | public ActionNote(AirAction parent) 69 | { 70 | parentNote = parent; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Ched.Core/Notes/Damage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | public class Damage : TappableBase 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ched.Core/Notes/ExTap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | public class ExTap : Tap 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ched.Core/Notes/Flick.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | public class Flick : TappableBase 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /Ched.Core/Notes/Hold.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 10 | public class Hold : MovableLongNoteBase 11 | { 12 | [Newtonsoft.Json.JsonProperty] 13 | private int laneIndex; 14 | [Newtonsoft.Json.JsonProperty] 15 | private int width = 1; 16 | [Newtonsoft.Json.JsonProperty] 17 | private int duration = 1; 18 | 19 | [Newtonsoft.Json.JsonProperty] 20 | private StartTap startNote; 21 | [Newtonsoft.Json.JsonProperty] 22 | private EndTap endNote; 23 | 24 | /// 25 | /// ノートの配置されるレーン番号を設定します。。 26 | /// 27 | public int LaneIndex 28 | { 29 | get { return laneIndex; } 30 | set 31 | { 32 | CheckPosition(value, Width); 33 | laneIndex = value; 34 | } 35 | } 36 | 37 | /// 38 | /// ノートのレーン幅を設定します。 39 | /// 40 | public int Width 41 | { 42 | get { return width; } 43 | set 44 | { 45 | CheckPosition(LaneIndex, value); 46 | width = value; 47 | } 48 | } 49 | 50 | /// 51 | /// ノートの長さを設定します。 52 | /// 53 | public int Duration 54 | { 55 | get { return duration; } 56 | set 57 | { 58 | if (duration == value) return; 59 | if (duration <= 0) throw new ArgumentOutOfRangeException("value", "value must be positive."); 60 | duration = value; 61 | } 62 | } 63 | 64 | protected void CheckPosition(int laneIndex, int width) 65 | { 66 | if (width < 1 || width > Constants.LanesCount) 67 | throw new ArgumentOutOfRangeException("width", "Invalid width."); 68 | if (laneIndex < 0 || laneIndex + width > Constants.LanesCount) 69 | throw new ArgumentOutOfRangeException("laneIndex", "Invalid lane index."); 70 | } 71 | 72 | public void SetPosition(int laneIndex, int width) 73 | { 74 | CheckPosition(laneIndex, width); 75 | this.laneIndex = laneIndex; 76 | this.width = width; 77 | } 78 | 79 | public StartTap StartNote { get { return startNote; } } 80 | public EndTap EndNote { get { return endNote; } } 81 | 82 | public Hold() 83 | { 84 | startNote = new StartTap(this); 85 | endNote = new EndTap(this); 86 | } 87 | 88 | public override int GetDuration() 89 | { 90 | return Duration; 91 | } 92 | 93 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 94 | public abstract class TapBase : LongNoteTapBase 95 | { 96 | protected Hold parent; 97 | 98 | public override int LaneIndex { get { return parent.LaneIndex; } } 99 | 100 | public override int Width { get { return parent.Width; } } 101 | 102 | public TapBase(Hold parent) 103 | { 104 | this.parent = parent; 105 | } 106 | } 107 | 108 | public class StartTap : TapBase 109 | { 110 | public override int Tick { get { return parent.StartTick; } } 111 | 112 | public override bool IsTap { get { return true; } } 113 | 114 | public StartTap(Hold parent) : base(parent) 115 | { 116 | } 117 | } 118 | 119 | public class EndTap : TapBase 120 | { 121 | public override bool IsTap { get { return false; } } 122 | 123 | public override int Tick { get { return parent.StartTick + parent.Duration; } } 124 | 125 | public EndTap(Hold parent) : base(parent) 126 | { 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Ched.Core/Notes/LongNoteBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | public interface ILongNote 10 | { 11 | /// 12 | /// ノートの開始位置を表すTickを設定します。 13 | /// 14 | int StartTick { get; } 15 | 16 | /// 17 | /// ノートの長さを表すTickを取得します。 18 | /// 19 | int GetDuration(); 20 | } 21 | 22 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 23 | public abstract class MovableLongNoteBase : ILongNote 24 | { 25 | [Newtonsoft.Json.JsonProperty] 26 | private int startTick; 27 | 28 | /// 29 | /// ノートの開始位置を表すTickを設定します。 30 | /// 31 | public int StartTick 32 | { 33 | get { return startTick; } 34 | set 35 | { 36 | if (startTick == value) return; 37 | if (value < 0) throw new ArgumentOutOfRangeException("value", "value must not be negative."); 38 | startTick = value; 39 | } 40 | } 41 | 42 | /// 43 | /// ノートの長さを表すTickを取得します。 44 | /// 45 | public abstract int GetDuration(); 46 | } 47 | 48 | public abstract class LongNoteTapBase : IAirable 49 | { 50 | public abstract bool IsTap { get; } 51 | public abstract int LaneIndex { get; } 52 | public abstract int Tick { get; } 53 | public abstract int Width { get; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Ched.Core/Notes/Tap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | public class Tap : TappableBase 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Ched.Core/Notes/TappableBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core.Notes 8 | { 9 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 10 | public abstract class TappableBase : IAirable 11 | { 12 | [Newtonsoft.Json.JsonProperty] 13 | private int tick; 14 | [Newtonsoft.Json.JsonProperty] 15 | private int laneIndex; 16 | [Newtonsoft.Json.JsonProperty] 17 | private int width = 1; 18 | 19 | /// 20 | /// ノートの位置を表すTickを設定します。 21 | /// 22 | public int Tick 23 | { 24 | get { return tick; } 25 | set 26 | { 27 | if (tick == value) return; 28 | if (tick < 0) throw new ArgumentOutOfRangeException("value", "value must not be negative."); 29 | tick = value; 30 | } 31 | } 32 | 33 | /// 34 | /// ノートの配置されるレーン番号を設定します。。 35 | /// 36 | public int LaneIndex 37 | { 38 | get { return laneIndex; } 39 | set 40 | { 41 | CheckPosition(value, Width); 42 | laneIndex = value; 43 | } 44 | } 45 | 46 | /// 47 | /// ノートのレーン幅を設定します。 48 | /// 49 | public int Width 50 | { 51 | get { return width; } 52 | set 53 | { 54 | CheckPosition(LaneIndex, value); 55 | width = value; 56 | } 57 | } 58 | 59 | protected void CheckPosition(int laneIndex, int width) 60 | { 61 | if (width < 1 || width > Constants.LanesCount) 62 | throw new ArgumentOutOfRangeException("width", "Invalid width."); 63 | if (laneIndex < 0 || laneIndex + width > Constants.LanesCount) 64 | throw new ArgumentOutOfRangeException("laneIndex", "Invalid lane index."); 65 | } 66 | 67 | public void SetPosition(int laneIndex, int width) 68 | { 69 | CheckPosition(laneIndex, width); 70 | this.laneIndex = laneIndex; 71 | this.width = width; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Ched.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("Ched.Core")] 6 | [assembly: AssemblyDescription("Ched Core Library")] 7 | [assembly: AssemblyCompany("paltee.net")] 8 | [assembly: AssemblyProduct("Ched.Core")] 9 | [assembly: AssemblyCopyright("Copyright (C) 2018 Paralleltree")] 10 | 11 | [assembly: ComVisible(false)] 12 | [assembly: Guid("5a5ff947-79dc-4352-94d5-eec14065f93a")] 13 | 14 | [assembly: AssemblyVersion("3.0.0.0")] 15 | -------------------------------------------------------------------------------- /Ched.Core/Score.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Core 8 | { 9 | /// 10 | /// 譜面データを表すクラスです。 11 | /// 12 | [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)] 13 | public class Score 14 | { 15 | [Newtonsoft.Json.JsonProperty] 16 | private int ticksPerBeat = 480; 17 | [Newtonsoft.Json.JsonProperty] 18 | private NoteCollection notes = new NoteCollection(); 19 | [Newtonsoft.Json.JsonProperty] 20 | private EventCollection events = new EventCollection(); 21 | 22 | /// 23 | /// 1拍あたりの分解能を設定します。 24 | /// 25 | public int TicksPerBeat 26 | { 27 | get { return ticksPerBeat; } 28 | set { ticksPerBeat = value; } 29 | } 30 | 31 | /// 32 | /// ノーツを格納するコレクションです。 33 | /// 34 | public NoteCollection Notes 35 | { 36 | get { return notes; } 37 | set { notes = value; } 38 | } 39 | 40 | /// 41 | /// イベントを格納するコレクションです。 42 | /// 43 | public EventCollection Events 44 | { 45 | get { return events; } 46 | set { events = value; } 47 | } 48 | 49 | public void UpdateTicksPerBeat(int value) 50 | { 51 | double factor = value / TicksPerBeat; 52 | Notes.UpdateTicksPerBeat(factor); 53 | Events.UpdateTicksPerBeat(factor); 54 | TicksPerBeat = value; 55 | } 56 | 57 | public Score Clone() 58 | { 59 | var score = Newtonsoft.Json.JsonConvert.DeserializeObject(Newtonsoft.Json.JsonConvert.SerializeObject(this, ScoreBook.SerializerSettings)); 60 | return score; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Ched.Core/TimeCalculator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core.Events; 8 | 9 | namespace Ched.Core 10 | { 11 | /// 12 | /// BPM変更イベントからTick値に対応する時刻を求めるクラスです。 13 | /// 14 | public class TimeCalculator 15 | { 16 | protected int TicksPerBeat { get; } 17 | // 時間順ソート済み 18 | protected List<(int Tick, double Bpm, double Time)> BpmDefinitions { get; } = new List<(int Tick, double Bpm, double Time)>(); 19 | 20 | public TimeCalculator(int ticksPerBeat, IEnumerable bpms) 21 | { 22 | TicksPerBeat = ticksPerBeat; 23 | double time = 0; 24 | var ordered = bpms.OrderBy(p => p.Tick).ToList(); 25 | if (ordered[0].Tick != 0) throw new ArgumentException("Initial BpmChangeEvent was not found.", "bpms"); 26 | BpmDefinitions.Add((0, ordered[0].Bpm, 0)); 27 | for (int i = 1; i < ordered.Count; i++) 28 | { 29 | time += GetDuration(ordered[i - 1].Bpm, ordered[i].Tick - ordered[i - 1].Tick); 30 | BpmDefinitions.Add((ordered[i].Tick, ordered[i].Bpm, time)); 31 | } 32 | } 33 | 34 | public double GetTimeFromTick(int tick) 35 | { 36 | for (int i = BpmDefinitions.Count - 1; 0 <= i; i--) 37 | { 38 | if (tick < BpmDefinitions[i].Tick) continue; 39 | return BpmDefinitions[i].Time + GetDuration(BpmDefinitions[i].Bpm, tick - BpmDefinitions[i].Tick); 40 | } 41 | // 負の時間は初期BPMで遡る 42 | return GetDuration(BpmDefinitions[0].Bpm, tick); 43 | } 44 | 45 | public int GetTickFromTime(double time) 46 | { 47 | for (int i = BpmDefinitions.Count - 1; 0 <= i; i--) 48 | { 49 | if (time < BpmDefinitions[i].Time) continue; 50 | return BpmDefinitions[i].Tick + GetDurationInTick(BpmDefinitions[i].Bpm, time - BpmDefinitions[i].Time); 51 | } 52 | // 負の時間は初期BPMで遡る 53 | return GetDurationInTick(BpmDefinitions[0].Bpm, time); 54 | } 55 | 56 | // => durationTick * (60 / bpm) / TicksPerBeat; 57 | protected double GetDuration(double bpm, int durationTick) => durationTick * 60 / bpm / TicksPerBeat; 58 | 59 | // => TicksPerBeat * duration * (bpm / 60) 60 | protected int GetDurationInTick(double bpm, double duration) => (int)(TicksPerBeat * duration * bpm / 60); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Ched.Core/UI/SelectionRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core; 8 | 9 | namespace Ched.UI 10 | { 11 | /// 12 | /// 選択範囲を表します。 13 | /// 14 | public struct SelectionRange 15 | { 16 | public static SelectionRange Empty = new SelectionRange() 17 | { 18 | StartTick = 0, 19 | Duration = 0, 20 | StartLaneIndex = 0, 21 | SelectedLanesCount = 0 22 | }; 23 | 24 | private int startTick; 25 | private int duration; 26 | private int startLaneIndex; 27 | private int selectedLanesCount; 28 | 29 | /// 30 | /// 選択を開始したTickを設定します。 31 | /// 32 | public int StartTick 33 | { 34 | get { return startTick; } 35 | set 36 | { 37 | if (value < 0) throw new ArgumentOutOfRangeException("value must not be negative."); 38 | startTick = value; 39 | } 40 | } 41 | 42 | /// 43 | /// 選択を終了したときのとのオフセットを表すTickを設定します。 44 | /// この値が負であるとき、よりも前の範囲が選択されたことを表します。 45 | /// 46 | public int Duration 47 | { 48 | get { return duration; } 49 | set 50 | { 51 | duration = value; 52 | } 53 | } 54 | 55 | /// 56 | /// 選択されたレーンの左端のインデックスを設定します。 57 | /// 58 | public int StartLaneIndex 59 | { 60 | get { return startLaneIndex; } 61 | set 62 | { 63 | if (value < 0 || value > Constants.LanesCount - 1) throw new ArgumentOutOfRangeException(); 64 | startLaneIndex = value; 65 | } 66 | } 67 | 68 | /// 69 | /// 選択されたレーン数を設定します。 70 | /// 71 | public int SelectedLanesCount 72 | { 73 | get { return selectedLanesCount; } 74 | set 75 | { 76 | if (StartLaneIndex + value < 0 || StartLaneIndex + value > Constants.LanesCount) throw new ArgumentOutOfRangeException(); 77 | selectedLanesCount = value; 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Ched.Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Ched.Drawing/Ched.Drawing.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A41EA7D5-9776-421B-A338-DD662287069B} 8 | Library 9 | Properties 10 | Ched.Drawing 11 | Ched.Drawing 12 | v4.8 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | true 35 | bin\x86\Debug\ 36 | DEBUG;TRACE 37 | full 38 | x86 39 | prompt 40 | MinimumRecommendedRules.ruleset 41 | 42 | 43 | bin\x86\Release\ 44 | TRACE 45 | true 46 | pdbonly 47 | x86 48 | prompt 49 | MinimumRecommendedRules.ruleset 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | {5a5ff947-79dc-4352-94d5-eec14065f93a} 68 | Ched.Core 69 | 70 | 71 | 72 | 73 | 74 | 75 | 82 | -------------------------------------------------------------------------------- /Ched.Drawing/Ched.Drawing.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $id$ 5 | $version$ 6 | $description$ 7 | $author$ 8 | 9 | https://github.com/paralleltree/Ched 10 | MIT 11 | false 12 | 13 | 14 | -------------------------------------------------------------------------------- /Ched.Drawing/ColorProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Drawing 9 | { 10 | public class GradientColor 11 | { 12 | public Color DarkColor { get; set; } 13 | public Color LightColor { get; set; } 14 | 15 | public GradientColor(Color darkColor, Color lightColor) 16 | { 17 | DarkColor = darkColor; 18 | LightColor = lightColor; 19 | } 20 | } 21 | 22 | public class ColorProfile 23 | { 24 | public GradientColor BorderColor { get; set; } 25 | public GradientColor TapColor { get; set; } 26 | public GradientColor ExTapColor { get; set; } 27 | 28 | /// 29 | /// フリックを描画する際のを指定します. 30 | /// Item1には背景色, Item2には前景色を指定します. 31 | /// 32 | public Tuple FlickColor { get; set; } 33 | public GradientColor DamageColor { get; set; } 34 | public GradientColor HoldBackgroundColor { get; set; } 35 | public GradientColor HoldColor { get; set; } 36 | public GradientColor SlideBackgroundColor { get; set; } 37 | public GradientColor SlideColor { get; set; } 38 | public Color SlideLineColor { get; set; } 39 | public GradientColor AirActionColor { get; set; } 40 | public Color AirUpColor { get; set; } 41 | public Color AirDownColor { get; set; } 42 | public Color AirHoldLineColor { get; set; } 43 | public GradientColor AirStepColor { get; set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Ched.Drawing/ComponentGraphics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Ched.Drawing 10 | { 11 | internal static class ComponentGraphics 12 | { 13 | public static void DrawTappableNote(this Graphics g, RectangleF rect, GradientColor foregroundColors, GradientColor borderColors) 14 | { 15 | g.DrawNote(rect, foregroundColors, borderColors); 16 | g.DrawTapSymbol(rect); 17 | } 18 | 19 | public static void DrawNote(this Graphics g, RectangleF rect, GradientColor foregroundColors, GradientColor borderColors) 20 | { 21 | DrawNoteBase(g, rect, foregroundColors); 22 | DrawBorder(g, rect, borderColors); 23 | } 24 | 25 | public static void DrawNoteBase(this Graphics g, RectangleF rect, GradientColor colors) 26 | { 27 | using (var path = rect.ToRoundedPath(rect.Height * 0.3f)) 28 | { 29 | using (var brush = new LinearGradientBrush(rect, colors.DarkColor, colors.LightColor, LinearGradientMode.Vertical)) 30 | { 31 | g.FillPath(brush, path); 32 | } 33 | } 34 | } 35 | 36 | public static void DrawBorder(this Graphics g, RectangleF rect, GradientColor colors) 37 | { 38 | float borderWidth = rect.Height * 0.1f; 39 | using (var brush = new LinearGradientBrush(rect.Expand(borderWidth), colors.DarkColor, colors.LightColor, LinearGradientMode.Vertical)) 40 | { 41 | using (var pen = new Pen(brush, borderWidth)) 42 | { 43 | using (var path = rect.ToRoundedPath(rect.Height * 0.3f)) 44 | { 45 | g.DrawPath(pen, path); 46 | } 47 | } 48 | } 49 | } 50 | 51 | public static void DrawSquarishNote(this Graphics g, RectangleF rect, GradientColor foregroundColors, GradientColor borderColors) 52 | { 53 | float borderWidth = rect.Height * 0.1f; 54 | using (var brush = new LinearGradientBrush(rect, foregroundColors.DarkColor, foregroundColors.LightColor, LinearGradientMode.Vertical)) 55 | { 56 | g.FillRectangle(brush, rect); 57 | } 58 | 59 | using (var brush = new LinearGradientBrush(rect.Expand(borderWidth), borderColors.DarkColor, borderColors.LightColor, LinearGradientMode.Vertical)) 60 | { 61 | using (var pen = new Pen(brush, borderWidth)) 62 | { 63 | g.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height); 64 | } 65 | } 66 | } 67 | 68 | public static void DrawTapSymbol(this Graphics g, RectangleF rect) 69 | { 70 | using (var pen = new Pen(Color.White, rect.Height * 0.1f)) 71 | { 72 | g.DrawLine(pen, rect.Left + rect.Width * 0.2f, rect.Top + rect.Height / 2f, rect.Right - rect.Width * 0.2f, rect.Top + rect.Height / 2); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Ched.Drawing/DrawingContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Drawing 9 | { 10 | public class DrawingContext 11 | { 12 | public Graphics Graphics { get; } 13 | public ColorProfile ColorProfile { get; } 14 | 15 | public DrawingContext(Graphics g, ColorProfile colorProfile) 16 | { 17 | Graphics = g; 18 | ColorProfile = colorProfile; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ched.Drawing/GraphicsExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Ched.Drawing 10 | { 11 | public static class GraphicsExtensions 12 | { 13 | // ref: http://csharphelper.com/blog/2016/01/draw-rounded-rectangles-in-c/ 14 | internal static GraphicsPath ToRoundedPath(this RectangleF rect, float radius) 15 | { 16 | if (radius * 2 > Math.Min(rect.Width, rect.Height)) 17 | { 18 | radius = Math.Min(rect.Width, rect.Height) / 2; 19 | } 20 | 21 | var path = new GraphicsPath(); 22 | 23 | path.AddArc(rect.Left, rect.Top, radius * 2, radius * 2, 180, 90); 24 | path.AddArc(rect.Right - radius * 2, rect.Top, radius * 2, radius * 2, 270, 90); 25 | path.AddArc(rect.Right - radius * 2, rect.Bottom - radius * 2, radius * 2, radius * 2, 0, 90); 26 | path.AddArc(rect.Left, rect.Bottom - radius * 2, radius * 2, radius * 2, 90, 90); 27 | path.CloseFigure(); 28 | return path; 29 | } 30 | 31 | public static RectangleF Expand(this RectangleF rect, float size) 32 | { 33 | return rect.Expand(size, size); 34 | } 35 | 36 | public static RectangleF Expand(this RectangleF rect, float dx, float dy) 37 | { 38 | return new RectangleF(rect.Left - dx, rect.Top - dy, rect.Width + dx * 2, rect.Height + dy * 2); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Ched.Drawing/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("Ched.Drawing")] 6 | [assembly: AssemblyDescription("Ched Drawing Library")] 7 | [assembly: AssemblyCompany("paltee.net")] 8 | [assembly: AssemblyProduct("Ched.Drawing")] 9 | [assembly: AssemblyCopyright("Copyright (C) 2018 Paralleltree")] 10 | 11 | [assembly: ComVisible(false)] 12 | [assembly: Guid("a41ea7d5-9776-421b-a338-dd662287069b")] 13 | 14 | [assembly: AssemblyVersion("3.0.0.0")] 15 | -------------------------------------------------------------------------------- /Ched.Plugins/Ched.Plugins.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BD335AFA-195D-4C2A-986A-167438C81976} 8 | Library 9 | Properties 10 | Ched.Plugins 11 | Ched.Plugins 12 | v4.8 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | true 35 | bin\x86\Debug\ 36 | DEBUG;TRACE 37 | full 38 | x86 39 | prompt 40 | MinimumRecommendedRules.ruleset 41 | 42 | 43 | bin\x86\Release\ 44 | TRACE 45 | true 46 | pdbonly 47 | x86 48 | prompt 49 | MinimumRecommendedRules.ruleset 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | {5a5ff947-79dc-4352-94d5-eec14065f93a} 68 | Ched.Core 69 | 70 | 71 | 72 | 73 | 74 | 75 | 82 | -------------------------------------------------------------------------------- /Ched.Plugins/Ched.Plugins.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $id$ 5 | $version$ 6 | $description$ 7 | $author$ 8 | 9 | https://github.com/paralleltree/Ched 10 | MIT 11 | false 12 | 13 | 14 | -------------------------------------------------------------------------------- /Ched.Plugins/Diagnostics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Plugins 8 | { 9 | public interface IDiagnosable 10 | { 11 | void ReportDiagnostic(Diagnostic diagnostic); 12 | } 13 | 14 | public class Diagnostic 15 | { 16 | public DiagnosticSeverity Severity { get; } 17 | public string Message { get; } 18 | 19 | public Diagnostic(DiagnosticSeverity severity, string message) 20 | { 21 | Severity = severity; 22 | Message = message; 23 | } 24 | } 25 | 26 | public enum DiagnosticSeverity 27 | { 28 | Hidden = 0, 29 | Information = 1, 30 | Warning = 2, 31 | Error = 3 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Ched.Plugins/IPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Plugins 8 | { 9 | /// 10 | /// アプリケーションで利用可能なプラグインを表します。 11 | /// 12 | public interface IPlugin 13 | { 14 | /// 15 | /// プラグインの表示名を取得します。 16 | /// 17 | string DisplayName { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Ched.Plugins/IScoreBookExportPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | using Ched.Core; 9 | 10 | namespace Ched.Plugins 11 | { 12 | /// 13 | /// 譜面データのエクスポートを行うプラグインを表します。 14 | /// 15 | public interface IScoreBookExportPlugin : IPlugin 16 | { 17 | /// 18 | /// ファイル選択ダイアログで利用するフィルタ文字列を取得します。 19 | /// 20 | string FileFilter { get; } 21 | 22 | /// 23 | /// エクスポート処理を実行します。 24 | /// 25 | /// エクスポート時の情報を取得する 26 | /// メソッドの呼び出し後に処理をキャンセルする場合、をスローします。 27 | void Export(IScoreBookExportPluginArgs args); 28 | } 29 | 30 | /// 31 | /// エクスポート時にプラグインへ渡される情報を表します。 32 | /// 33 | public interface IScoreBookExportPluginArgs : IDiagnosable 34 | { 35 | /// 36 | /// データを書き込むを取得します。 37 | /// 38 | Stream Stream { get; } 39 | 40 | /// 41 | /// 追加情報を入力する必要があるかどうかを示す値を取得します。 42 | /// この値がTrueの場合、追加情報を要求するダイアログを表示する必要はありません。 43 | /// 44 | bool IsQuick { get; } 45 | 46 | /// 47 | /// エクスポートするデータを取得します。 48 | /// 49 | /// エクスポートする譜面データを表す 50 | ScoreBook GetScoreBook(); 51 | 52 | /// 53 | /// エクスポートされるデータに関連付けられた追加情報を取得します。 54 | /// 55 | /// 追加情報を表す文字列 56 | string GetCustomData(); 57 | 58 | /// 59 | /// エクスポートしたデータに関連付ける追加情報を保存します。 60 | /// 61 | /// 保存する追加情報を表す文字列 62 | void SetCustomData(string data); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Ched.Plugins/IScoreBookImportPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.IO; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | using Ched.Core; 9 | 10 | namespace Ched.Plugins 11 | { 12 | /// 13 | /// 譜面データのインポートを行うプラグインを表します。 14 | /// 15 | public interface IScoreBookImportPlugin : IPlugin 16 | { 17 | /// 18 | /// ファイル選択時に利用するフィルタ文字列を取得します。 19 | /// 20 | string FileFilter { get; } 21 | 22 | /// 23 | /// 譜面データのインポート処理を行います。 24 | /// 25 | /// インポート時に渡される情報を表す 26 | /// インポートされる譜面を表す 27 | ScoreBook Import(IScoreBookImportPluginArgs args); 28 | } 29 | 30 | /// 31 | /// 譜面データのインポート時に渡される情報を表します。 32 | /// 33 | public interface IScoreBookImportPluginArgs : IDiagnosable 34 | { 35 | /// 36 | /// データを読み取るストリームを取得します。 37 | /// 38 | Stream Stream { get; } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Ched.Plugins/IScorePlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core; 8 | using Ched.UI; 9 | 10 | namespace Ched.Plugins 11 | { 12 | /// 13 | /// 譜面データを扱うプラグインを表します。 14 | /// 15 | public interface IScorePlugin : IPlugin 16 | { 17 | void Run(IScorePluginArgs args); 18 | } 19 | 20 | /// 21 | /// の実行時に渡される情報を表します。 22 | /// 23 | public interface IScorePluginArgs 24 | { 25 | Score GetCurrentScore(); 26 | SelectionRange GetSelectedRange(); 27 | void UpdateScore(Score score); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Ched.Plugins/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("Ched.Plugins")] 6 | [assembly: AssemblyDescription("Ched Plugin Support Library")] 7 | [assembly: AssemblyCompany("paltee.net")] 8 | [assembly: AssemblyProduct("Ched.Plugins")] 9 | [assembly: AssemblyCopyright("Copyright (C) 2018 Paralleltree")] 10 | 11 | [assembly: ComVisible(false)] 12 | [assembly: Guid("bd335afa-195d-4c2a-986a-167438c81976")] 13 | 14 | [assembly: AssemblyVersion("3.0.0.0")] 15 | -------------------------------------------------------------------------------- /Ched.Plugins/UserCancelledException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.Plugins 8 | { 9 | [Serializable] 10 | public class UserCancelledException : Exception 11 | { 12 | public UserCancelledException() 13 | { 14 | } 15 | 16 | public UserCancelledException(string message) : base(message) 17 | { 18 | } 19 | 20 | public UserCancelledException(string message, Exception inner) : base(message, inner) 21 | { 22 | } 23 | 24 | protected UserCancelledException( 25 | System.Runtime.Serialization.SerializationInfo info, 26 | System.Runtime.Serialization.StreamingContext context) : base(info, context) 27 | { 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Ched.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ched", "Ched\Ched.csproj", "{4C0C9F98-6FCF-4D2F-B821-37A66362DC75}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ched.Drawing", "Ched.Drawing\Ched.Drawing.csproj", "{A41EA7D5-9776-421B-A338-DD662287069B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ched.Core", "Ched.Core\Ched.Core.csproj", "{5A5FF947-79DC-4352-94D5-EEC14065F93A}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ched.Plugins", "Ched.Plugins\Ched.Plugins.csproj", "{BD335AFA-195D-4C2A-986A-167438C81976}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|x86 = Debug|x86 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {4C0C9F98-6FCF-4D2F-B821-37A66362DC75}.Debug|x86.ActiveCfg = Debug|x86 21 | {4C0C9F98-6FCF-4D2F-B821-37A66362DC75}.Debug|x86.Build.0 = Debug|x86 22 | {4C0C9F98-6FCF-4D2F-B821-37A66362DC75}.Release|x86.ActiveCfg = Release|x86 23 | {4C0C9F98-6FCF-4D2F-B821-37A66362DC75}.Release|x86.Build.0 = Release|x86 24 | {A41EA7D5-9776-421B-A338-DD662287069B}.Debug|x86.ActiveCfg = Debug|Any CPU 25 | {A41EA7D5-9776-421B-A338-DD662287069B}.Debug|x86.Build.0 = Debug|Any CPU 26 | {A41EA7D5-9776-421B-A338-DD662287069B}.Release|x86.ActiveCfg = Release|Any CPU 27 | {A41EA7D5-9776-421B-A338-DD662287069B}.Release|x86.Build.0 = Release|Any CPU 28 | {5A5FF947-79DC-4352-94D5-EEC14065F93A}.Debug|x86.ActiveCfg = Debug|Any CPU 29 | {5A5FF947-79DC-4352-94D5-EEC14065F93A}.Debug|x86.Build.0 = Debug|Any CPU 30 | {5A5FF947-79DC-4352-94D5-EEC14065F93A}.Release|x86.ActiveCfg = Release|Any CPU 31 | {5A5FF947-79DC-4352-94D5-EEC14065F93A}.Release|x86.Build.0 = Release|Any CPU 32 | {BD335AFA-195D-4C2A-986A-167438C81976}.Debug|x86.ActiveCfg = Debug|Any CPU 33 | {BD335AFA-195D-4C2A-986A-167438C81976}.Debug|x86.Build.0 = Debug|Any CPU 34 | {BD335AFA-195D-4C2A-986A-167438C81976}.Release|x86.ActiveCfg = Release|Any CPU 35 | {BD335AFA-195D-4C2A-986A-167438C81976}.Release|x86.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /Ched/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | False 29 | 30 | 31 | 120 32 | 33 | 34 | False 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Ched/Configuration/ApplicationSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Configuration; 7 | 8 | namespace Ched.Configuration 9 | { 10 | internal sealed class ApplicationSettings : SettingsBase 11 | { 12 | public static ApplicationSettings Default { get; } = (ApplicationSettings)Synchronized(new ApplicationSettings()); 13 | 14 | private ApplicationSettings() 15 | { 16 | } 17 | 18 | [UserScopedSetting] 19 | [DefaultSettingValue("12")] 20 | public int UnitLaneWidth 21 | { 22 | get { return ((int)(this["UnitLaneWidth"])); } 23 | set { this["UnitLaneWidth"] = value; } 24 | } 25 | 26 | [UserScopedSetting] 27 | [DefaultSettingValue("120")] 28 | public int UnitBeatHeight 29 | { 30 | get { return ((int)(this["UnitBeatHeight"])); } 31 | set { this["UnitBeatHeight"] = value; } 32 | } 33 | 34 | [UserScopedSetting] 35 | [DefaultSettingValue("True")] 36 | public bool InsertAirWithAirAction 37 | { 38 | get { return ((bool)(this["InsertAirWithAirAction"])); } 39 | set { this["InsertAirWithAirAction"] = value; } 40 | } 41 | 42 | [UserScopedSetting] 43 | [DefaultSettingValue("False")] 44 | public bool IsPreviewAbortAtLastNote 45 | { 46 | get { return ((bool)(this["IsPreviewAbortAtLastNote"])); } 47 | set { this["IsPreviewAbortAtLastNote"] = value; } 48 | } 49 | 50 | [UserScopedSetting] 51 | [DefaultSettingValue("False")] 52 | public bool IsSlowDownPreviewEnabled 53 | { 54 | get => (bool)this["IsSlowDownPreviewEnabled"]; 55 | set => this["IsSlowDownPreviewEnabled"] = value; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Ched/Configuration/SettingsBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Configuration; 7 | 8 | namespace Ched.Configuration 9 | { 10 | internal interface IUpgradable 11 | { 12 | bool HasUpgraded { get; } 13 | } 14 | 15 | internal abstract class SettingsBase : ApplicationSettingsBase, IUpgradable 16 | { 17 | [UserScopedSetting] 18 | [DefaultSettingValue("False")] 19 | public bool HasUpgraded 20 | { 21 | get { return (bool)this["HasUpgraded"]; } 22 | private set { this["HasUpgraded"] = value; } 23 | } 24 | 25 | public override void Upgrade() 26 | { 27 | base.Upgrade(); 28 | HasUpgraded = true; 29 | Save(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Ched/Configuration/SoundSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Configuration; 7 | 8 | using Ched.UI; 9 | 10 | namespace Ched.Configuration 11 | { 12 | internal sealed class SoundSettings : SettingsBase 13 | { 14 | public static SoundSettings Default { get; } = (SoundSettings)Synchronized(new SoundSettings()); 15 | 16 | private SoundSettings() 17 | { 18 | } 19 | 20 | // ref: https://stackoverflow.com/a/12807699 21 | [UserScopedSetting] 22 | [SettingsSerializeAs(SettingsSerializeAs.Binary)] 23 | [DefaultSettingValue("")] // empty dictionary 24 | public Dictionary ScoreSound 25 | { 26 | get { return (Dictionary)this["ScoreSound"]; } 27 | set { this["ScoreSound"] = value; } 28 | } 29 | 30 | [UserScopedSetting] 31 | public SoundSource GuideSound 32 | { 33 | get => (SoundSource)this["GuideSound"] ?? new SoundSource("guide.mp3", 0.036); 34 | set => this["GuideSound"] = value; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Ched/Localization/FileFilterStrings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Ched.Localization { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public class FileFilterStrings { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal FileFilterStrings() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | public static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ched.Localization.FileFilterStrings", typeof(FileFilterStrings).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to 音声ファイル. 65 | /// 66 | public static string AudioFilter { 67 | get { 68 | return ResourceManager.GetString("AudioFilter", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Ched専用形式. 74 | /// 75 | public static string ChedFilter { 76 | get { 77 | return ResourceManager.GetString("ChedFilter", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to 画像ファイル. 83 | /// 84 | public static string ImageFilter { 85 | get { 86 | return ResourceManager.GetString("ImageFilter", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Ched/Localization/MainFormStrings.en.Designer.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Localization/MainFormStrings.en.Designer.cs -------------------------------------------------------------------------------- /Ched/Localization/PluginStrings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Ched.Localization { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public class PluginStrings { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal PluginStrings() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | public static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ched.Localization.PluginStrings", typeof(PluginStrings).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to コンボ計算. 65 | /// 66 | public static string ComboCalculator { 67 | get { 68 | return ResourceManager.GetString("ComboCalculator", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to スライド編み込み. 74 | /// 75 | public static string SlideKnitter { 76 | get { 77 | return ResourceManager.GetString("SlideKnitter", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to スライド結合. 83 | /// 84 | public static string SlideMerger { 85 | get { 86 | return ResourceManager.GetString("SlideMerger", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Looks up a localized string similar to スライド時間軸反転. 92 | /// 93 | public static string SlideReverser { 94 | get { 95 | return ResourceManager.GetString("SlideReverser", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// Looks up a localized string similar to スライド分割. 101 | /// 102 | public static string SlideSplitter { 103 | get { 104 | return ResourceManager.GetString("SlideSplitter", resourceCulture); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Ched/Localization/PluginStrings.en.Designer.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Localization/PluginStrings.en.Designer.cs -------------------------------------------------------------------------------- /Ched/Plugins/ExportManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | using Ched.Core; 9 | 10 | namespace Ched.Plugins 11 | { 12 | internal class ExportManager 13 | { 14 | private ExportContext LastUsedContext { get; set; } 15 | private Dictionary CustomDataCache { get; set; } 16 | 17 | public bool CanReExport => LastUsedContext != null; 18 | 19 | protected void Initialize() 20 | { 21 | LastUsedContext = null; 22 | CustomDataCache = null; 23 | } 24 | 25 | public void Load(ScoreBook book) 26 | { 27 | Initialize(); 28 | CustomDataCache = book.ExportArgs; 29 | } 30 | 31 | public ExportContext PrepareExport(IScoreBookExportPlugin plugin, string dest) 32 | { 33 | return PrepareExport(plugin, dest, false); 34 | } 35 | 36 | public ExportContext PrepareReExport() 37 | { 38 | if (!CanReExport) throw new InvalidOperationException(); 39 | return PrepareExport(LastUsedContext.ExportPlugin, LastUsedContext.OutputPath, true); 40 | } 41 | 42 | protected ExportContext PrepareExport(IScoreBookExportPlugin plugin, string dest, bool isQuick) 43 | { 44 | string name = ResolvePluginName(plugin); 45 | return new ExportContext(plugin, dest, isQuick, () => CustomDataCache.ContainsKey(name) ? CustomDataCache[name] : "", data => CustomDataCache[name] = data); 46 | } 47 | 48 | /// 49 | /// エクスポートが正常に完了したことをこのへ通知します。 50 | /// 51 | /// エクスポートを行った 52 | public void CommitExported(ExportContext context) => LastUsedContext = context; 53 | 54 | protected string ResolvePluginName(IScoreBookExportPlugin plugin) => plugin.GetType().FullName; 55 | } 56 | 57 | internal class ExportContext 58 | { 59 | public IScoreBookExportPlugin ExportPlugin { get; } 60 | protected bool IsQuick { get; } 61 | public string OutputPath { get; } 62 | protected readonly Func GetCustomData; 63 | protected readonly Action SetCustomData; 64 | public IReadOnlyCollection Diagnostics { get; private set; } 65 | 66 | public ExportContext(IScoreBookExportPlugin plugin, string dest, bool isQuick, Func getCustomData, Action setCustomData) 67 | { 68 | ExportPlugin = plugin; 69 | IsQuick = isQuick; 70 | OutputPath = dest; 71 | GetCustomData = getCustomData; 72 | SetCustomData = setCustomData; 73 | } 74 | 75 | public void Export(ScoreBook book) 76 | { 77 | using (var ms = new MemoryStream()) 78 | { 79 | var args = new ScoreBookExportPluginArgs(book, ms, IsQuick, GetCustomData, SetCustomData); 80 | Diagnostics = args.Diagnostics; 81 | ExportPlugin.Export(args); 82 | using (var fs = new FileStream(OutputPath, FileMode.Create, FileAccess.Write)) 83 | { 84 | var res = ms.ToArray(); 85 | fs.Write(res, 0, res.Length); 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Ched/Plugins/PluginManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.IO; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | using System.ComponentModel.Composition; 9 | using System.ComponentModel.Composition.Hosting; 10 | using System.ComponentModel.Composition.Registration; 11 | using System.Reflection; 12 | 13 | namespace Ched.Plugins 14 | { 15 | public class PluginManager 16 | { 17 | internal static string PluginPath => "Plugins"; 18 | 19 | [ImportMany] 20 | IEnumerable scorePlugins = Enumerable.Empty(); 21 | [ImportMany] 22 | IEnumerable bookImportPlugins = Enumerable.Empty(); 23 | [ImportMany] 24 | IEnumerable bookExportPlugins = Enumerable.Empty(); 25 | 26 | public IReadOnlyCollection FailedFiles { get; private set; } = new List(); 27 | public IReadOnlyCollection InvalidFiles { get; private set; } = new List(); 28 | 29 | public IEnumerable ScorePlugins => scorePlugins; 30 | public IEnumerable ScoreBookImportPlugins => bookImportPlugins; 31 | public IEnumerable ScoreBookExportPlugins => bookExportPlugins; 32 | 33 | private PluginManager() 34 | { 35 | } 36 | 37 | public static PluginManager GetInstance() 38 | { 39 | var builder = new RegistrationBuilder(); 40 | builder.ForTypesDerivedFrom().ExportInterfaces(); 41 | builder.ForType().Export(); 42 | 43 | var failedFiles = new List(); 44 | var self = new AssemblyCatalog(typeof(PluginManager).Assembly, builder); 45 | var catalog = new AggregateCatalog(self); 46 | 47 | if (Directory.Exists(PluginPath)) 48 | { 49 | foreach (string path in new DirectoryInfo(PluginPath).GetFiles().Select(p => p.FullName).Where(p => p.ToLower().EndsWith(".dll"))) 50 | { 51 | try 52 | { 53 | var assembly = System.Reflection.Assembly.LoadFile(path); 54 | catalog.Catalogs.Add(new AssemblyCatalog(assembly, builder)); 55 | } 56 | catch (Exception ex) when (ex is NotSupportedException || ex is BadImageFormatException) 57 | { 58 | failedFiles.Add(GetRelativePluginPath(path)); 59 | } 60 | } 61 | } 62 | 63 | var container = new CompositionContainer(catalog); 64 | PluginManager manager = null; 65 | try 66 | { 67 | manager = container.GetExportedValue(); 68 | } 69 | catch (ReflectionTypeLoadException ex) when (ex.LoaderExceptions.Any(p => p is TypeLoadException)) 70 | { 71 | return new PluginManager() 72 | { 73 | FailedFiles = failedFiles, 74 | InvalidFiles = ex.Types.Where(p => p != null).Select(p => GetRelativePluginPath(p.Assembly.Location)).Distinct().ToList() 75 | }; 76 | } 77 | manager.FailedFiles = failedFiles; 78 | return manager; 79 | } 80 | 81 | private static string GetRelativePluginPath(string path) => Uri.UnescapeDataString(new Uri(Path.GetFullPath(PluginPath)).MakeRelativeUri(new Uri(path)).ToString().Replace('/', Path.DirectorySeparatorChar)); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Ched/Plugins/ScoreBookExportPluginArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | using Ched.Core; 9 | 10 | namespace Ched.Plugins 11 | { 12 | public class ScoreBookExportPluginArgs : IScoreBookExportPluginArgs 13 | { 14 | private readonly List _diagnostics = new List(); 15 | private ScoreBook ScoreBook { get; } 16 | private Func getCustomDataFunc { get; } 17 | private Action setCustomDataFunc { get; } 18 | 19 | public IReadOnlyCollection Diagnostics => _diagnostics; 20 | public Stream Stream { get; } 21 | public bool IsQuick { get; } 22 | 23 | public ScoreBookExportPluginArgs(ScoreBook scoreBook, Stream stream, bool isQuick, Func getCustomDataFunc, Action setCustomDataFunc) 24 | { 25 | ScoreBook = scoreBook; 26 | Stream = stream; 27 | IsQuick = isQuick; 28 | this.getCustomDataFunc = getCustomDataFunc; 29 | this.setCustomDataFunc = setCustomDataFunc; 30 | } 31 | 32 | public ScoreBook GetScoreBook() => ScoreBook.Clone(); 33 | 34 | public string GetCustomData() => getCustomDataFunc(); 35 | 36 | public void SetCustomData(string data) => setCustomDataFunc(data); 37 | 38 | public void ReportDiagnostic(Diagnostic diagnostic) 39 | { 40 | _diagnostics.Add(diagnostic); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Ched/Plugins/ScoreBookImportPluginArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Ched.Plugins 9 | { 10 | public class ScoreBookImportPluginArgs : IScoreBookImportPluginArgs 11 | { 12 | private readonly List _diagnostics = new List(); 13 | public IReadOnlyCollection Diagnostics => _diagnostics; 14 | public Stream Stream { get; } 15 | 16 | public ScoreBookImportPluginArgs(Stream stream) 17 | { 18 | Stream = stream; 19 | } 20 | 21 | public void ReportDiagnostic(Diagnostic diagnostic) 22 | { 23 | _diagnostics.Add(diagnostic); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Ched/Plugins/ScorePluginArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core; 8 | using Ched.Core.Events; 9 | using Ched.UI; 10 | 11 | namespace Ched.Plugins 12 | { 13 | public class ScorePluginArgs : IScorePluginArgs 14 | { 15 | private Func getScoreFunc; 16 | private SelectionRange selectedRange; 17 | private Action updateScoreAction; 18 | 19 | public ScorePluginArgs(Func getScoreFunc, SelectionRange selectedRange, Action updateScoreAction) 20 | { 21 | this.getScoreFunc = getScoreFunc; 22 | this.selectedRange = selectedRange; 23 | this.updateScoreAction = updateScoreAction; 24 | } 25 | 26 | public Score GetCurrentScore() => getScoreFunc(); 27 | 28 | public SelectionRange GetSelectedRange() => selectedRange; 29 | 30 | public void UpdateScore(Score score) 31 | { 32 | CheckEventDuplicate(score.Events.BpmChangeEvents); 33 | CheckEventDuplicate(score.Events.TimeSignatureChangeEvents); 34 | CheckEventDuplicate(score.Events.HighSpeedChangeEvents); 35 | updateScoreAction(score); 36 | } 37 | 38 | private void CheckEventDuplicate(IList src) where T : EventBase 39 | { 40 | var set = new HashSet(); 41 | if (src.All(p => set.Add(p.Tick))) return; 42 | throw new ArgumentException("There are some events in same ticks."); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Ched/Plugins/ShiftEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | using Ched.Core; 9 | using Ched.Core.Events; 10 | using Ched.Localization; 11 | using Ched.UI; 12 | 13 | namespace Ched.Plugins 14 | { 15 | public class ShiftEvent : IScorePlugin 16 | { 17 | public string DisplayName => "イベント移動"; 18 | 19 | public void Run(IScorePluginArgs args) 20 | { 21 | var form = new ShiftTimeSelectionForm(); 22 | if (form.ShowDialog() != DialogResult.OK) return; 23 | if (form.CountValue == 0) return; 24 | 25 | var score = args.GetCurrentScore(); 26 | int origin = args.GetSelectedRange().StartTick; 27 | BarIndexCalculator barIndexCalculator; 28 | try 29 | { 30 | barIndexCalculator = new BarIndexCalculator(score.TicksPerBeat, score.Events.TimeSignatureChangeEvents); 31 | } 32 | catch (InvalidTimeSignatureException ex) 33 | { 34 | int beatAt = ex.Tick / score.TicksPerBeat + 1; 35 | MessageBox.Show(string.Format(ErrorStrings.InvalidTimeSignature, beatAt), DisplayName, MessageBoxButtons.OK, MessageBoxIcon.Warning); 36 | return; 37 | } 38 | var barIndex = barIndexCalculator.GetBarPositionFromTick(origin).BarIndex; 39 | var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(barIndex); 40 | int offset = 4 * score.TicksPerBeat * form.CountValue * (form.DurationType == DurationType.Bar ? sig.Numerator : 1) / sig.Denominator; 41 | 42 | var (heading, targets) = Partition(score.Events.AllEvents.Where(p => p.Tick > 0), p => p.Tick <= origin); 43 | if (targets.Count == 0) return; 44 | int firstEventTick = targets.Min(p => p.Tick); 45 | int lowerLimitTick = heading.Count == 0 ? 0 : heading.Max(p => p.Tick); 46 | 47 | if (offset < 0 && firstEventTick + offset <= lowerLimitTick) 48 | { 49 | MessageBox.Show("移動対象のイベントが先行するイベントを追い越すため、移動は実行されません。", DisplayName, MessageBoxButtons.OK, MessageBoxIcon.Warning); 50 | return; 51 | } 52 | 53 | foreach (var item in targets) item.Tick += offset; 54 | 55 | args.UpdateScore(score); 56 | } 57 | 58 | protected (IList, IList) Partition(IEnumerable collection, Func predicate) 59 | { 60 | var trueList = new List(); 61 | var falseList = new List(); 62 | foreach (var item in collection) (predicate(item) ? trueList : falseList).Add(item); 63 | return (trueList, falseList); 64 | } 65 | 66 | public enum DurationType 67 | { 68 | Bar, 69 | Beat 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Ched/Plugins/SlideKnitter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Localization; 8 | 9 | namespace Ched.Plugins 10 | { 11 | public class SlideKnitter : IScorePlugin 12 | { 13 | public string DisplayName => PluginStrings.SlideKnitter; 14 | 15 | public void Run(IScorePluginArgs args) 16 | { 17 | var score = args.GetCurrentScore(); 18 | var range = args.GetSelectedRange(); 19 | var slides = score.Notes.Slides 20 | .Where(p => p.StartTick <= range.StartTick && p.StepNotes.OrderByDescending(q => q.Tick).First().Tick >= range.StartTick); 21 | 22 | foreach (var slide in slides.Where(p => p.StepNotes.Count == 3)) 23 | { 24 | var steps = slide.StepNotes.OrderBy(p => p.TickOffset).ToList(); 25 | // 始点と2つ目の中継点間の時間が等しいものが対象 26 | int initInterval = steps[0].TickOffset; 27 | if (initInterval * 2 != steps[1].TickOffset) continue; 28 | 29 | bool stepVisible = steps[0].IsVisible; 30 | int duration = steps[steps.Count - 1].TickOffset; 31 | int stepsCount = duration / initInterval; 32 | for (int i = 0; i < stepsCount - 2; i++) 33 | { 34 | int pos = initInterval * (i + 3); 35 | if (pos >= duration) break; 36 | var step = new Core.Notes.Slide.StepTap(slide) 37 | { 38 | TickOffset = pos, 39 | IsVisible = stepVisible 40 | }; 41 | step.SetPosition(steps[i % 2].LaneIndexOffset, steps[i % 2].WidthChange); 42 | slide.StepNotes.Add(step); 43 | } 44 | } 45 | 46 | args.UpdateScore(score); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Ched/Plugins/SlideReverser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core.Notes; 8 | using Ched.Localization; 9 | 10 | namespace Ched.Plugins 11 | { 12 | public class SlideReverser : IScorePlugin 13 | { 14 | public string DisplayName => PluginStrings.SlideReverser; 15 | 16 | public void Run(IScorePluginArgs args) 17 | { 18 | var score = args.GetCurrentScore(); 19 | var range = args.GetSelectedRange(); 20 | int startTick = range.Duration < 0 ? range.StartTick + range.Duration : range.StartTick; 21 | int endTick = range.Duration < 0 ? range.StartTick : range.StartTick + range.Duration; 22 | var endStepDic = score.Notes.Slides.ToDictionary(p => p, p => p.StepNotes.OrderByDescending(q => q.TickOffset).First()); 23 | var airStepDic = score.Notes.Airs 24 | .Where(p => endStepDic.Values.Contains(p.ParentNote)) 25 | .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p); 26 | var airActionStepDic = score.Notes.AirActions 27 | .Where(p => endStepDic.Values.Contains(p.ParentNote)) 28 | .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p); 29 | 30 | var targets = score.Notes.Slides 31 | .Where(p => p.StartTick >= startTick && p.StartTick + p.GetDuration() <= endTick) 32 | .Where(p => p.StartLaneIndex >= range.StartLaneIndex && p.StartLaneIndex + p.StartWidth <= range.StartLaneIndex + range.SelectedLanesCount) 33 | .Where(p => p.StepNotes.All(q => q.LaneIndex >= range.StartLaneIndex && q.LaneIndex + q.Width <= range.StartLaneIndex + range.SelectedLanesCount)) 34 | .Where(p => !airStepDic.ContainsKey(endStepDic[p]) && !airActionStepDic.ContainsKey(endStepDic[p])) 35 | .ToList(); 36 | if (targets.Count == 0) return; 37 | var results = targets.Select(p => 38 | { 39 | var ordered = p.StepNotes.OrderByDescending(q => q.TickOffset).ToList(); 40 | var res = new Slide() { StartTick = startTick + (endTick - ordered[0].Tick) }; 41 | res.SetPosition(ordered[0].LaneIndex, ordered[0].Width); 42 | var trailing = new Slide.StepTap(res) { IsVisible = true, TickOffset = startTick + (endTick - p.StartTick) - res.StartTick }; 43 | trailing.SetPosition(p.StartLaneIndex - res.StartLaneIndex, p.StartWidth - res.StartWidth); 44 | var steps = ordered.Skip(1).Select(q => 45 | { 46 | var step = new Slide.StepTap(res) { IsVisible = q.IsVisible, TickOffset = startTick + (endTick - q.Tick) - res.StartTick }; 47 | step.SetPosition(q.LaneIndex - res.StartLaneIndex, q.Width - res.StartWidth); 48 | return step; 49 | }) 50 | .Concat(new[] { trailing }); 51 | res.StepNotes.AddRange(steps); 52 | return res; 53 | }); 54 | 55 | foreach (var slide in targets) score.Notes.Slides.Remove(slide); 56 | score.Notes.Slides.AddRange(results); 57 | args.UpdateScore(score); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Ched/Plugins/SlideSplitter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core.Notes; 8 | using Ched.Localization; 9 | 10 | namespace Ched.Plugins 11 | { 12 | public class SlideSplitter : IScorePlugin 13 | { 14 | public string DisplayName => PluginStrings.SlideSplitter; 15 | 16 | public void Run(IScorePluginArgs args) 17 | { 18 | var score = args.GetCurrentScore(); 19 | var range = args.GetSelectedRange(); 20 | bool modified = false; 21 | var targets = score.Notes.Slides.Where(p => p.StartTick < range.StartTick && p.StepNotes.OrderByDescending(q => q.TickOffset).First().Tick > range.StartTick); 22 | var endStepDic = score.Notes.Slides.ToDictionary(p => p, p => p.StepNotes.OrderByDescending(q => q.TickOffset).First()); 23 | var airStepDic = score.Notes.Airs 24 | .Where(p => endStepDic.Values.Contains(p.ParentNote)) 25 | .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p); 26 | var airActionStepDic = score.Notes.AirActions 27 | .Where(p => endStepDic.Values.Contains(p.ParentNote)) 28 | .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p); 29 | 30 | foreach (var slide in targets.ToList()) 31 | { 32 | // カーソル位置に中継点が存在しなければ処理しない 33 | int offset = range.StartTick - slide.StartTick; 34 | if (slide.StepNotes.All(p => p.TickOffset != offset)) continue; 35 | 36 | var first = new Slide() { StartTick = slide.StartTick }; 37 | first.SetPosition(slide.StartLaneIndex, slide.StartWidth); 38 | first.StepNotes.AddRange(slide.StepNotes.OrderBy(p => p.TickOffset).TakeWhile(p => p.TickOffset <= offset).Select(p => 39 | { 40 | var step = new Slide.StepTap(first) { TickOffset = p.TickOffset, IsVisible = p.IsVisible }; 41 | step.SetPosition(p.LaneIndexOffset, p.WidthChange); 42 | return step; 43 | })); 44 | first.StepNotes[first.StepNotes.Count - 1].IsVisible = true; 45 | 46 | var second = new Slide() { StartTick = range.StartTick }; 47 | var trailing = slide.StepNotes.OrderBy(p => p.TickOffset).SkipWhile(p => p.TickOffset < offset).ToList(); 48 | second.SetPosition(trailing[0].LaneIndex, trailing[0].Width); 49 | second.StepNotes.AddRange(trailing.Skip(1).Select(p => 50 | { 51 | var step = new Slide.StepTap(second) { TickOffset = p.TickOffset - offset, IsVisible = p.IsVisible }; 52 | step.SetPosition(p.LaneIndex - second.StartLaneIndex, p.Width - second.StartWidth); 53 | return step; 54 | })); 55 | 56 | // 終点AIRをsecondに挿入 57 | if (airStepDic.ContainsKey(endStepDic[slide])) 58 | { 59 | var origAir = airStepDic[endStepDic[slide]]; 60 | var air = new Air(second.StepNotes[second.StepNotes.Count - 1]) 61 | { 62 | VerticalDirection = origAir.VerticalDirection, 63 | HorizontalDirection = origAir.HorizontalDirection 64 | }; 65 | score.Notes.Airs.Remove(origAir); 66 | score.Notes.Airs.Add(air); 67 | } 68 | if (airActionStepDic.ContainsKey(endStepDic[slide])) 69 | { 70 | var origAirAction = airActionStepDic[endStepDic[slide]]; 71 | var airAction = new AirAction(second.StepNotes[second.StepNotes.Count - 1]); 72 | airAction.ActionNotes.AddRange(origAirAction.ActionNotes.Select(p => new AirAction.ActionNote(airAction) { Offset = p.Offset })); 73 | score.Notes.AirActions.Remove(origAirAction); 74 | score.Notes.AirActions.Add(airAction); 75 | } 76 | 77 | score.Notes.Slides.Add(first); 78 | score.Notes.Slides.Add(second); 79 | score.Notes.Slides.Remove(slide); 80 | modified = true; 81 | } 82 | if (modified) args.UpdateScore(score); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Ched/Plugins/SusExportPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | using Newtonsoft.Json; 9 | using Ched.Components.Exporter; 10 | using Ched.UI.Windows; 11 | 12 | namespace Ched.Plugins 13 | { 14 | public class SusExportPlugin : IScoreBookExportPlugin 15 | { 16 | public string DisplayName => "Sliding Universal Score (*.sus)"; 17 | 18 | public string FileFilter => "Sliding Universal Score (*.sus)|*.sus"; 19 | 20 | public void Export(IScoreBookExportPluginArgs args) 21 | { 22 | var book = args.GetScoreBook(); 23 | SusArgs susArgs = JsonConvert.DeserializeObject(args.GetCustomData() ?? "") ?? new SusArgs(); 24 | if (!args.IsQuick) 25 | { 26 | var vm = new SusExportWindowViewModel(book, susArgs); 27 | var window = new SusExportWindow() { DataContext = vm }; 28 | var result = window.ShowDialog(); 29 | if (!result.HasValue || !result.Value) throw new UserCancelledException(); 30 | args.SetCustomData(JsonConvert.SerializeObject(susArgs)); 31 | } 32 | 33 | var exporter = new SusExporter(book, susArgs); 34 | exporter.Export(args.Stream); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Ched/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.IO; 5 | using System.Reflection; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | using Ched.Configuration; 10 | 11 | namespace Ched 12 | { 13 | static class Program 14 | { 15 | internal static readonly string ApplicationName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name; 16 | 17 | /// 18 | /// The main entry point for the application. 19 | /// 20 | [STAThread] 21 | static void Main(string[] args) 22 | { 23 | Directory.SetCurrentDirectory(Path.GetDirectoryName(Application.ExecutablePath)); 24 | 25 | #if !DEBUG 26 | Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); 27 | AppDomain.CurrentDomain.UnhandledException += (s, e) => DumpException((Exception)e.ExceptionObject, true); 28 | #endif 29 | 30 | AppDomain.CurrentDomain.AssemblyResolve += (s, e) => 31 | { 32 | string path = Path.Combine(Plugins.PluginManager.PluginPath, new AssemblyName(e.Name).Name + ".dll"); 33 | return File.Exists(path) ? Assembly.LoadFrom(path) : null; 34 | }; 35 | 36 | UpgradeConfiguration(ApplicationSettings.Default); 37 | UpgradeConfiguration(SoundSettings.Default); 38 | 39 | Application.EnableVisualStyles(); 40 | Application.SetCompatibleTextRenderingDefault(false); 41 | Application.Run(args.Length == 0 ? new UI.MainForm() : new UI.MainForm(args[0])); 42 | } 43 | 44 | public static void DumpExceptionTo(Exception ex, string filename) 45 | { 46 | try 47 | { 48 | File.WriteAllText(filename, Newtonsoft.Json.JsonConvert.SerializeObject(ex)); 49 | } 50 | catch (UnauthorizedAccessException) 51 | { 52 | } 53 | } 54 | 55 | public static void DumpException(Exception ex) 56 | { 57 | DumpException(ex, false); 58 | } 59 | 60 | public static void DumpException(Exception ex, bool forceClose) 61 | { 62 | DumpExceptionTo(ex, "exception.json"); 63 | if (!forceClose) return; 64 | try 65 | { 66 | MessageBox.Show("エラーが発生しました。\nアプリケーションを終了します。", ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); 67 | } 68 | finally 69 | { 70 | Environment.Exit(1); 71 | } 72 | } 73 | 74 | private static bool UpgradeConfiguration(SettingsBase setting) 75 | { 76 | try 77 | { 78 | if (!setting.HasUpgraded) setting.Upgrade(); 79 | } 80 | catch (Exception ex) 81 | { 82 | DumpExceptionTo(ex, "configuration_exeption.json"); 83 | setting.Reset(); 84 | return false; 85 | } 86 | return true; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Ched/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using System.Windows.Media; 5 | 6 | [assembly: AssemblyTitle("Ched")] 7 | [assembly: AssemblyDescription("Yet Another Chart Editor")] 8 | [assembly: AssemblyCompany("paltee.net")] 9 | [assembly: AssemblyProduct("Ched")] 10 | [assembly: AssemblyCopyright("Copyright (C) 2017 Paralleltree")] 11 | 12 | [assembly: ComVisible(false)] 13 | [assembly: Guid("4c0c9f98-6fcf-4d2f-b821-37a66362dc75")] 14 | 15 | [assembly: AssemblyVersion("3.2.0.0")] 16 | 17 | [assembly: DisableDpiAwareness] 18 | -------------------------------------------------------------------------------- /Ched/Resources/airaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/airaction.png -------------------------------------------------------------------------------- /Ched/Resources/airdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/airdown.png -------------------------------------------------------------------------------- /Ched/Resources/airleftdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/airleftdown.png -------------------------------------------------------------------------------- /Ched/Resources/airleftup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/airleftup.png -------------------------------------------------------------------------------- /Ched/Resources/airrightdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/airrightdown.png -------------------------------------------------------------------------------- /Ched/Resources/airrightup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/airrightup.png -------------------------------------------------------------------------------- /Ched/Resources/airup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/airup.png -------------------------------------------------------------------------------- /Ched/Resources/arrow-curve-180-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/arrow-curve-180-left.png -------------------------------------------------------------------------------- /Ched/Resources/arrow-curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/arrow-curve.png -------------------------------------------------------------------------------- /Ched/Resources/blue-document-export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/blue-document-export.png -------------------------------------------------------------------------------- /Ched/Resources/clipboard-paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/clipboard-paste.png -------------------------------------------------------------------------------- /Ched/Resources/cross-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/cross-circle.png -------------------------------------------------------------------------------- /Ched/Resources/damage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/damage.png -------------------------------------------------------------------------------- /Ched/Resources/disk-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/disk-black.png -------------------------------------------------------------------------------- /Ched/Resources/document--plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/document--plus.png -------------------------------------------------------------------------------- /Ched/Resources/document-copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/document-copy.png -------------------------------------------------------------------------------- /Ched/Resources/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/eraser.png -------------------------------------------------------------------------------- /Ched/Resources/exclamation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/exclamation.png -------------------------------------------------------------------------------- /Ched/Resources/extap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/extap.png -------------------------------------------------------------------------------- /Ched/Resources/flick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/flick.png -------------------------------------------------------------------------------- /Ched/Resources/folder-horizontal-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/folder-horizontal-open.png -------------------------------------------------------------------------------- /Ched/Resources/guide.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/guide.mp3 -------------------------------------------------------------------------------- /Ched/Resources/hold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/hold.png -------------------------------------------------------------------------------- /Ched/Resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/icon.ico -------------------------------------------------------------------------------- /Ched/Resources/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/information.png -------------------------------------------------------------------------------- /Ched/Resources/magnifier-zoom-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/magnifier-zoom-in.png -------------------------------------------------------------------------------- /Ched/Resources/magnifier-zoom-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/magnifier-zoom-out.png -------------------------------------------------------------------------------- /Ched/Resources/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/pencil.png -------------------------------------------------------------------------------- /Ched/Resources/scissors-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/scissors-blue.png -------------------------------------------------------------------------------- /Ched/Resources/selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/selection.png -------------------------------------------------------------------------------- /Ched/Resources/slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/slide.png -------------------------------------------------------------------------------- /Ched/Resources/slidestep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/slidestep.png -------------------------------------------------------------------------------- /Ched/Resources/tap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paralleltree/Ched/fa880077e9e82fa87e03f20f398daf2303f29a81/Ched/Resources/tap.png -------------------------------------------------------------------------------- /Ched/UI/BpmSelectionForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Ched.UI 2 | { 3 | partial class BpmSelectionForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BpmSelectionForm)); 32 | this.buttonOK = new System.Windows.Forms.Button(); 33 | this.buttonCancel = new System.Windows.Forms.Button(); 34 | this.bpmBox = new System.Windows.Forms.NumericUpDown(); 35 | this.label1 = new System.Windows.Forms.Label(); 36 | ((System.ComponentModel.ISupportInitialize)(this.bpmBox)).BeginInit(); 37 | this.SuspendLayout(); 38 | // 39 | // buttonOK 40 | // 41 | resources.ApplyResources(this.buttonOK, "buttonOK"); 42 | this.buttonOK.Name = "buttonOK"; 43 | this.buttonOK.UseVisualStyleBackColor = true; 44 | // 45 | // buttonCancel 46 | // 47 | resources.ApplyResources(this.buttonCancel, "buttonCancel"); 48 | this.buttonCancel.Name = "buttonCancel"; 49 | this.buttonCancel.UseVisualStyleBackColor = true; 50 | // 51 | // bpmBox 52 | // 53 | resources.ApplyResources(this.bpmBox, "bpmBox"); 54 | this.bpmBox.Name = "bpmBox"; 55 | // 56 | // label1 57 | // 58 | resources.ApplyResources(this.label1, "label1"); 59 | this.label1.Name = "label1"; 60 | // 61 | // BpmSelectionForm 62 | // 63 | resources.ApplyResources(this, "$this"); 64 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 65 | this.Controls.Add(this.label1); 66 | this.Controls.Add(this.bpmBox); 67 | this.Controls.Add(this.buttonCancel); 68 | this.Controls.Add(this.buttonOK); 69 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 70 | this.MaximizeBox = false; 71 | this.MinimizeBox = false; 72 | this.Name = "BpmSelectionForm"; 73 | ((System.ComponentModel.ISupportInitialize)(this.bpmBox)).EndInit(); 74 | this.ResumeLayout(false); 75 | this.PerformLayout(); 76 | 77 | } 78 | 79 | #endregion 80 | 81 | private System.Windows.Forms.Button buttonOK; 82 | private System.Windows.Forms.Button buttonCancel; 83 | private System.Windows.Forms.NumericUpDown bpmBox; 84 | private System.Windows.Forms.Label label1; 85 | } 86 | } -------------------------------------------------------------------------------- /Ched/UI/BpmSelectionForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Ched.UI 12 | { 13 | public partial class BpmSelectionForm : Form 14 | { 15 | public double Bpm 16 | { 17 | get => (double)bpmBox.Value; 18 | set 19 | { 20 | bpmBox.Value = (decimal)value; 21 | bpmBox.SelectAll(); 22 | } 23 | } 24 | 25 | public BpmSelectionForm() 26 | { 27 | InitializeComponent(); 28 | AcceptButton = buttonOK; 29 | CancelButton = buttonCancel; 30 | buttonOK.DialogResult = DialogResult.OK; 31 | buttonCancel.DialogResult = DialogResult.Cancel; 32 | 33 | bpmBox.DecimalPlaces = 0; 34 | bpmBox.Increment = 1; 35 | bpmBox.Maximum = 10000; 36 | bpmBox.Minimum = 10; 37 | bpmBox.Value = 120; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Ched/UI/CheckableToolStripSplitButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using System.Windows.Forms.VisualStyles; 8 | 9 | namespace Ched.UI 10 | { 11 | // https://arstechnica.com/civis/viewtopic.php?f=20&t=311656 12 | public class CheckableToolStripSplitButton : ToolStripSplitButton 13 | { 14 | private bool _Checked = false; 15 | private VisualStyleRenderer renderer = null; 16 | private readonly VisualStyleElement element = VisualStyleElement.ToolBar.Button.Checked; 17 | 18 | public CheckableToolStripSplitButton() 19 | { 20 | if (Application.RenderWithVisualStyles && VisualStyleRenderer.IsElementDefined(element)) 21 | { 22 | renderer = new VisualStyleRenderer(element); 23 | } 24 | } 25 | 26 | public bool Checked 27 | { 28 | get 29 | { 30 | return _Checked; 31 | } 32 | set 33 | { 34 | _Checked = value; 35 | this.Invalidate(); 36 | } 37 | } 38 | 39 | protected override void OnPaint(PaintEventArgs e) 40 | { 41 | if (_Checked) 42 | { 43 | if (renderer != null) 44 | { 45 | System.Drawing.Rectangle cr = base.ContentRectangle; 46 | System.Drawing.Image img = this.Image; 47 | 48 | // Compute the center of the item's ContentRectangle. 49 | int centerY = (cr.Height - img.Height) / 2; 50 | System.Drawing.Rectangle fullRect = new System.Drawing.Rectangle(0, 0, this.Width, this.Height); 51 | 52 | System.Drawing.Rectangle imageRect = new System.Drawing.Rectangle( 53 | base.ContentRectangle.Left, 54 | centerY, 55 | base.Image.Width, 56 | base.Image.Height); 57 | 58 | System.Drawing.Rectangle textRect = new System.Drawing.Rectangle( 59 | imageRect.Width, 60 | base.ContentRectangle.Top, 61 | base.ContentRectangle.Width - (imageRect.Width + 10), 62 | base.ContentRectangle.Height); 63 | 64 | renderer.DrawBackground(e.Graphics, fullRect); 65 | //renderer.DrawText(e.Graphics, textRect, this.Text); 66 | //renderer.DrawImage(e.Graphics, imageRect, this.Image); 67 | base.OnPaint(e); 68 | } 69 | else 70 | { 71 | e.Graphics.FillRectangle(System.Drawing.SystemBrushes.Control, 0, 0, this.Width, this.Height); 72 | e.Graphics.DrawRectangle(new System.Drawing.Pen(System.Drawing.SystemColors.Highlight), 0, 0, this.Width - 1, this.Height - 1); 73 | base.OnPaint(e); 74 | } 75 | } 76 | else 77 | { 78 | base.OnPaint(e); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Ched/UI/ControlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using System.Reactive.Linq; 8 | 9 | namespace Ched.UI 10 | { 11 | internal static class ControlExtensions 12 | { 13 | public static LayoutManager WorkWithLayout(this Control control) 14 | { 15 | return new LayoutManager(control); 16 | } 17 | 18 | public static void InvokeIfRequired(this Control control, Action action) 19 | { 20 | if (control.InvokeRequired) control.Invoke((MethodInvoker)(() => action())); 21 | else action(); 22 | } 23 | 24 | public static IObservable MouseDownAsObservable(this Control control) 25 | { 26 | return Observable.FromEvent( 27 | h => (o, e) => h(e), 28 | h => control.MouseDown += h, 29 | h => control.MouseDown -= h); 30 | } 31 | 32 | public static IObservable MouseMoveAsObservable(this Control control) 33 | { 34 | return Observable.FromEvent( 35 | h => (o, e) => h(e), 36 | h => control.MouseMove += h, 37 | h => control.MouseMove -= h); 38 | } 39 | 40 | public static IObservable MouseUpAsObservable(this Control control) 41 | { 42 | return Observable.FromEvent( 43 | h => (o, e) => h(e), 44 | h => control.MouseUp += h, 45 | h => control.MouseUp -= h); 46 | } 47 | 48 | public static int GetMaximumValue(this ScrollBar scrollbar) 49 | { 50 | return scrollbar.Maximum - scrollbar.LargeChange + 1; 51 | } 52 | 53 | public static void SelectAll(this NumericUpDown control) 54 | { 55 | control.Select(0, control.Text.Length); 56 | } 57 | } 58 | 59 | internal class LayoutManager : IDisposable 60 | { 61 | protected Control _control; 62 | 63 | public LayoutManager(Control control) 64 | { 65 | control.SuspendLayout(); 66 | _control = control; 67 | } 68 | 69 | public void Dispose() 70 | { 71 | _control.ResumeLayout(false); 72 | _control.PerformLayout(); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Ched/UI/CustomQuantizeSelectionForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Ched.UI 2 | { 3 | partial class CustomQuantizeSelectionForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CustomQuantizeSelectionForm)); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.label2 = new System.Windows.Forms.Label(); 34 | this.noteLengthBox = new System.Windows.Forms.ComboBox(); 35 | this.noteDivisionBox = new System.Windows.Forms.NumericUpDown(); 36 | this.buttonOK = new System.Windows.Forms.Button(); 37 | this.buttonCancel = new System.Windows.Forms.Button(); 38 | ((System.ComponentModel.ISupportInitialize)(this.noteDivisionBox)).BeginInit(); 39 | this.SuspendLayout(); 40 | // 41 | // label1 42 | // 43 | resources.ApplyResources(this.label1, "label1"); 44 | this.label1.Name = "label1"; 45 | // 46 | // label2 47 | // 48 | resources.ApplyResources(this.label2, "label2"); 49 | this.label2.Name = "label2"; 50 | // 51 | // noteLengthBox 52 | // 53 | this.noteLengthBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 54 | this.noteLengthBox.FormattingEnabled = true; 55 | resources.ApplyResources(this.noteLengthBox, "noteLengthBox"); 56 | this.noteLengthBox.Name = "noteLengthBox"; 57 | // 58 | // noteDivisionBox 59 | // 60 | resources.ApplyResources(this.noteDivisionBox, "noteDivisionBox"); 61 | this.noteDivisionBox.Name = "noteDivisionBox"; 62 | // 63 | // buttonOK 64 | // 65 | resources.ApplyResources(this.buttonOK, "buttonOK"); 66 | this.buttonOK.Name = "buttonOK"; 67 | this.buttonOK.UseVisualStyleBackColor = true; 68 | // 69 | // buttonCancel 70 | // 71 | resources.ApplyResources(this.buttonCancel, "buttonCancel"); 72 | this.buttonCancel.Name = "buttonCancel"; 73 | this.buttonCancel.UseVisualStyleBackColor = true; 74 | // 75 | // CustomQuantizeSelectionForm 76 | // 77 | resources.ApplyResources(this, "$this"); 78 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 79 | this.Controls.Add(this.buttonCancel); 80 | this.Controls.Add(this.buttonOK); 81 | this.Controls.Add(this.noteDivisionBox); 82 | this.Controls.Add(this.noteLengthBox); 83 | this.Controls.Add(this.label2); 84 | this.Controls.Add(this.label1); 85 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 86 | this.MaximizeBox = false; 87 | this.MinimizeBox = false; 88 | this.Name = "CustomQuantizeSelectionForm"; 89 | ((System.ComponentModel.ISupportInitialize)(this.noteDivisionBox)).EndInit(); 90 | this.ResumeLayout(false); 91 | this.PerformLayout(); 92 | 93 | } 94 | 95 | #endregion 96 | 97 | private System.Windows.Forms.Label label1; 98 | private System.Windows.Forms.Label label2; 99 | private System.Windows.Forms.ComboBox noteLengthBox; 100 | private System.Windows.Forms.NumericUpDown noteDivisionBox; 101 | private System.Windows.Forms.Button buttonOK; 102 | private System.Windows.Forms.Button buttonCancel; 103 | } 104 | } -------------------------------------------------------------------------------- /Ched/UI/CustomQuantizeSelectionForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Ched.UI 12 | { 13 | public partial class CustomQuantizeSelectionForm : Form 14 | { 15 | private int BarTick { get; } 16 | 17 | public double QuantizeTick 18 | { 19 | get 20 | { 21 | return Math.Max(BarTick / Math.Pow(2, noteLengthBox.SelectedIndex) / (int)noteDivisionBox.Value, 1); 22 | } 23 | } 24 | 25 | public CustomQuantizeSelectionForm(int barTick) 26 | { 27 | InitializeComponent(); 28 | AcceptButton = buttonOK; 29 | CancelButton = buttonCancel; 30 | buttonOK.DialogResult = DialogResult.OK; 31 | buttonCancel.DialogResult = DialogResult.Cancel; 32 | 33 | BarTick = barTick; 34 | 35 | noteLengthBox.Items.AddRange(Enumerable.Range(0, 7).Select(p => ((int)Math.Pow(2, p)).ToString()).ToArray()); 36 | noteLengthBox.SelectedIndex = 2; 37 | 38 | noteDivisionBox.Minimum = 1; 39 | noteDivisionBox.Maximum = 30; 40 | noteDivisionBox.Value = 1; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Ched/UI/GraphicsExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Drawing; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace Ched.UI 10 | { 11 | internal static class GraphicsExtensions 12 | { 13 | [DllImport("gdi32.dll")] 14 | private static extern int SetROP2(IntPtr hdc, int enDrawMode); 15 | 16 | [DllImport("gdi32.dll")] 17 | private static extern IntPtr CreatePen(PenStyles enPenStyle, int nWidth, int crColor); 18 | 19 | [DllImport("gdi32.dll")] 20 | private static extern bool DeleteObject(IntPtr hObject); 21 | 22 | [DllImport("gdi32.dll")] 23 | private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject); 24 | 25 | [DllImport("gdi32.dll")] 26 | private static extern bool Rectangle(IntPtr hdc, int x1, int y1, int x2, int y2); 27 | 28 | [DllImport("gdi32.dll")] 29 | private static extern IntPtr GetStockObject(int brStyle); 30 | 31 | private const int NULL_BRUSH = 5; 32 | private const int BLACK_PEN = 0; 33 | private const int R2_XORPEN = 7; 34 | 35 | // ref: https://www.codeproject.com/Articles/4958/Combining-GDI-and-GDI-to-Draw-Rubber-Band-Rectangl 36 | public static void DrawXorRectangle(this Graphics g, PenStyles style, int x1, int y1, int x2, int y2) 37 | { 38 | IntPtr hdc = g.GetHdc(); 39 | IntPtr pen = CreatePen(style, 1, BLACK_PEN); 40 | 41 | SetROP2(hdc, R2_XORPEN); 42 | 43 | IntPtr oldPen = SelectObject(hdc, pen); 44 | IntPtr oldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH)); 45 | 46 | Rectangle(hdc, x1, y1, x2, y2); 47 | 48 | SelectObject(hdc, oldBrush); 49 | SelectObject(hdc, oldPen); 50 | DeleteObject(pen); 51 | 52 | g.ReleaseHdc(hdc); 53 | } 54 | 55 | public static void DrawXorRectangle(this Graphics g, PenStyles style, Point start, Point end) 56 | { 57 | g.DrawXorRectangle(style, start.X, start.Y, end.X, end.Y); 58 | } 59 | } 60 | 61 | internal enum PenStyles 62 | { 63 | Solid = 0, 64 | Dash = 1, 65 | Dot = 2, 66 | DashDot = 3, 67 | DashDotDot = 4 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Ched/UI/Helpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.UI 8 | { 9 | public static class Helpers 10 | { 11 | public static string GetFilterString(string kind, IEnumerable extensions) 12 | { 13 | var wildcards = extensions.Select(p => "*" + p); 14 | return kind + string.Format("({0})|{1}", string.Join(", ", wildcards), string.Join(";", wildcards)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Ched/UI/HighSpeedSelectionForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Ched.UI 2 | { 3 | partial class HighSpeedSelectionForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HighSpeedSelectionForm)); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.speedRatioBox = new System.Windows.Forms.NumericUpDown(); 34 | this.buttonOK = new System.Windows.Forms.Button(); 35 | this.buttonCancel = new System.Windows.Forms.Button(); 36 | ((System.ComponentModel.ISupportInitialize)(this.speedRatioBox)).BeginInit(); 37 | this.SuspendLayout(); 38 | // 39 | // label1 40 | // 41 | resources.ApplyResources(this.label1, "label1"); 42 | this.label1.Name = "label1"; 43 | // 44 | // speedRatioBox 45 | // 46 | resources.ApplyResources(this.speedRatioBox, "speedRatioBox"); 47 | this.speedRatioBox.Name = "speedRatioBox"; 48 | // 49 | // buttonOK 50 | // 51 | resources.ApplyResources(this.buttonOK, "buttonOK"); 52 | this.buttonOK.Name = "buttonOK"; 53 | this.buttonOK.UseVisualStyleBackColor = true; 54 | // 55 | // buttonCancel 56 | // 57 | resources.ApplyResources(this.buttonCancel, "buttonCancel"); 58 | this.buttonCancel.Name = "buttonCancel"; 59 | this.buttonCancel.UseVisualStyleBackColor = true; 60 | // 61 | // HighSpeedSelectionForm 62 | // 63 | resources.ApplyResources(this, "$this"); 64 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 65 | this.Controls.Add(this.buttonCancel); 66 | this.Controls.Add(this.buttonOK); 67 | this.Controls.Add(this.speedRatioBox); 68 | this.Controls.Add(this.label1); 69 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 70 | this.MaximizeBox = false; 71 | this.MinimizeBox = false; 72 | this.Name = "HighSpeedSelectionForm"; 73 | ((System.ComponentModel.ISupportInitialize)(this.speedRatioBox)).EndInit(); 74 | this.ResumeLayout(false); 75 | this.PerformLayout(); 76 | 77 | } 78 | 79 | #endregion 80 | 81 | private System.Windows.Forms.Label label1; 82 | private System.Windows.Forms.NumericUpDown speedRatioBox; 83 | private System.Windows.Forms.Button buttonOK; 84 | private System.Windows.Forms.Button buttonCancel; 85 | } 86 | } -------------------------------------------------------------------------------- /Ched/UI/HighSpeedSelectionForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Ched.UI 12 | { 13 | public partial class HighSpeedSelectionForm : Form 14 | { 15 | public decimal SpeedRatio 16 | { 17 | get { return speedRatioBox.Value; } 18 | set 19 | { 20 | speedRatioBox.Value = value; 21 | speedRatioBox.SelectAll(); 22 | } 23 | } 24 | 25 | public HighSpeedSelectionForm() 26 | { 27 | InitializeComponent(); 28 | AcceptButton = buttonOK; 29 | CancelButton = buttonCancel; 30 | buttonOK.DialogResult = DialogResult.OK; 31 | buttonCancel.DialogResult = DialogResult.Cancel; 32 | 33 | speedRatioBox.Minimum = -10000m; 34 | speedRatioBox.Maximum = 10000m; 35 | speedRatioBox.Increment = 0.01m; 36 | speedRatioBox.DecimalPlaces = 2; 37 | speedRatioBox.Value = 1; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Ched/UI/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Ched.UI 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing) 17 | { 18 | if (components != null) components.Dispose(); 19 | 20 | PreviewManager.Dispose(); 21 | base.Dispose(disposing); 22 | } 23 | } 24 | 25 | #region Windows Form Designer generated code 26 | 27 | /// 28 | /// Required method for Designer support - do not modify 29 | /// the contents of this method with the code editor. 30 | /// 31 | private void InitializeComponent() 32 | { 33 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); 34 | this.SuspendLayout(); 35 | // 36 | // MainForm 37 | // 38 | resources.ApplyResources(this, "$this"); 39 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 40 | this.Name = "MainForm"; 41 | this.ResumeLayout(false); 42 | 43 | } 44 | 45 | #endregion 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /Ched/UI/NoteView.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Ched.UI 2 | { 3 | partial class NoteView 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing) 17 | { 18 | if (components != null) 19 | { 20 | components.Dispose(); 21 | } 22 | 23 | Subscriptions.Dispose(); 24 | } 25 | base.Dispose(disposing); 26 | } 27 | 28 | #region Component Designer generated code 29 | 30 | /// 31 | /// Required method for Designer support - do not modify 32 | /// the contents of this method with the code editor. 33 | /// 34 | private void InitializeComponent() 35 | { 36 | components = new System.ComponentModel.Container(); 37 | } 38 | 39 | #endregion 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Ched/UI/Operations/CompositeOperation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.UI.Operations 8 | { 9 | /// 10 | /// 複数のからなる1つの操作を表します。 11 | /// 12 | public class CompositeOperation : IOperation 13 | { 14 | public string Description { get; } 15 | 16 | protected IEnumerable Operations { get; } 17 | 18 | /// 19 | /// 操作の説明とからこのを初期化します。 20 | /// 21 | /// この操作の説明 22 | /// 操作順にソートされた 23 | public CompositeOperation(string description, IEnumerable operations) 24 | { 25 | Description = description; 26 | Operations = operations; 27 | } 28 | 29 | public void Redo() 30 | { 31 | foreach (var op in Operations) op.Redo(); 32 | } 33 | 34 | public void Undo() 35 | { 36 | foreach (var op in Operations.Reverse()) op.Undo(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Ched/UI/Operations/EventCollectionOperation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core.Events; 8 | 9 | namespace Ched.UI.Operations 10 | { 11 | public abstract class EventCollectionOperation : IOperation where T : EventBase 12 | { 13 | protected T Event { get; } 14 | protected List Collection { get; } 15 | public abstract string Description { get; } 16 | 17 | public EventCollectionOperation(List collection, T item) 18 | { 19 | Collection = collection; 20 | Event = item; 21 | } 22 | 23 | public abstract void Redo(); 24 | public abstract void Undo(); 25 | } 26 | 27 | public class InsertEventOperation : EventCollectionOperation where T : EventBase 28 | { 29 | public override string Description { get { return "イベントの挿入"; } } 30 | 31 | public InsertEventOperation(List collection, T item) : base(collection, item) 32 | { 33 | } 34 | 35 | public override void Redo() 36 | { 37 | Collection.Add(Event); 38 | } 39 | 40 | public override void Undo() 41 | { 42 | Collection.Remove(Event); 43 | } 44 | } 45 | 46 | public class RemoveEventOperation : EventCollectionOperation where T : EventBase 47 | { 48 | public override string Description { get { return "イベントの削除"; } } 49 | 50 | public RemoveEventOperation(List collection, T item) : base(collection, item) 51 | { 52 | } 53 | 54 | public override void Redo() 55 | { 56 | Collection.Remove(Event); 57 | } 58 | 59 | public override void Undo() 60 | { 61 | Collection.Add(Event); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Ched/UI/Operations/IOperation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.UI.Operations 8 | { 9 | /// 10 | /// ユーザーの操作を表すインタフェースです。 11 | /// 12 | public interface IOperation 13 | { 14 | /// 15 | /// この操作の説明を取得します。 16 | /// 17 | string Description { get; } 18 | 19 | /// 20 | /// 操作を元に戻します。 21 | /// 22 | void Undo(); 23 | 24 | /// 25 | /// 操作をやり直します。 26 | /// 27 | void Redo(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Ched/UI/Operations/OperationManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.UI.Operations 8 | { 9 | /// 10 | /// 操作を管理するクラスです。 11 | /// 12 | public class OperationManager 13 | { 14 | public event EventHandler OperationHistoryChanged; 15 | public event EventHandler ChangesCommitted; 16 | 17 | protected Stack UndoStack { get; } = new Stack(); 18 | protected Stack RedoStack { get; } = new Stack(); 19 | 20 | private IOperation LastCommittedOperation { get; set; } = null; 21 | 22 | /// 23 | /// 元に戻す操作の概要のコレクションを取得します。 24 | /// 25 | public IEnumerable UndoOperationsDescription 26 | { 27 | get { return UndoStack.Select(p => p.Description); } 28 | } 29 | 30 | /// 31 | /// やり直す操作の概要のコレクションを取得します。 32 | /// 33 | public IEnumerable RedoOperationsDescription 34 | { 35 | get { return RedoStack.Select(p => p.Description); } 36 | } 37 | 38 | /// 39 | /// 操作を元に戻せるかどうかを取得します。 40 | /// 41 | public bool CanUndo { get { return UndoStack.Count > 0; } } 42 | 43 | /// 44 | /// 操作をやり直せるかどうかを取得します。 45 | /// 46 | public bool CanRedo { get { return RedoStack.Count > 0; } } 47 | 48 | /// 49 | /// 前回のの呼び出しから変更が加えられているかどうかを取得します。 50 | /// 51 | public bool IsChanged { get { return LastCommittedOperation != (UndoStack.Count > 0 ? UndoStack.Peek() : null); } } 52 | 53 | /// 54 | /// 新たな操作を記録します。 55 | /// 56 | /// 記録する操作 57 | public void Push(IOperation op) 58 | { 59 | UndoStack.Push(op); 60 | RedoStack.Clear(); 61 | OperationHistoryChanged?.Invoke(this, EventArgs.Empty); 62 | } 63 | 64 | /// 65 | /// 操作を実行し、記録します。 66 | /// 67 | /// 実行・記録する操作 68 | public void InvokeAndPush(IOperation op) 69 | { 70 | op.Redo(); 71 | Push(op); 72 | } 73 | 74 | /// 75 | /// 直前の操作を元に戻します。 76 | /// 77 | public void Undo() 78 | { 79 | IOperation op = UndoStack.Pop(); 80 | op.Undo(); 81 | RedoStack.Push(op); 82 | OperationHistoryChanged?.Invoke(this, EventArgs.Empty); 83 | } 84 | 85 | /// 86 | /// 直後の操作をやり直します。 87 | /// 88 | public void Redo() 89 | { 90 | IOperation op = RedoStack.Pop(); 91 | op.Redo(); 92 | UndoStack.Push(op); 93 | OperationHistoryChanged?.Invoke(this, EventArgs.Empty); 94 | } 95 | 96 | /// 97 | /// 記録されている操作をクリアします。 98 | /// 99 | public void Clear() 100 | { 101 | UndoStack.Clear(); 102 | RedoStack.Clear(); 103 | LastCommittedOperation = null; 104 | OperationHistoryChanged?.Invoke(this, EventArgs.Empty); 105 | } 106 | 107 | /// 108 | /// 現在のの状態に対して、保存処理が行われたことを通知します。 109 | /// 110 | public void CommitChanges() 111 | { 112 | LastCommittedOperation = UndoStack.Count > 0 ? UndoStack.Peek() : null; 113 | ChangesCommitted?.Invoke(this, EventArgs.Empty); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Ched/UI/Operations/ScoreOperation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Ched.Core; 8 | 9 | namespace Ched.UI.Operations 10 | { 11 | public class UpdateScoreOperation : IOperation 12 | { 13 | public string Description { get { return "譜面の更新"; } } 14 | 15 | protected Action setScoreAction; 16 | protected Score BeforeScore { get; } 17 | protected Score AfterScore { get; } 18 | 19 | public UpdateScoreOperation(Score beforeScore, Score afterScore, Action setScoreAction) 20 | { 21 | BeforeScore = beforeScore; 22 | AfterScore = afterScore; 23 | this.setScoreAction = setScoreAction; 24 | } 25 | 26 | public void Undo() 27 | { 28 | setScoreAction(BeforeScore); 29 | } 30 | 31 | public void Redo() 32 | { 33 | setScoreAction(AfterScore); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Ched/UI/PlaneExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Ched.UI 10 | { 11 | public static class PlaneExtensions 12 | { 13 | public static RectangleF GetLeftThumb(this RectangleF rect, float widthRate, float minimumWidth) 14 | { 15 | return new RectangleF(rect.X, rect.Y, Math.Max(rect.Width * widthRate, minimumWidth), rect.Height); 16 | } 17 | 18 | public static RectangleF GetRightThumb(this RectangleF rect, float widthRate, float minimumWidth) 19 | { 20 | float width = Math.Max(rect.Width * widthRate, minimumWidth); 21 | return new RectangleF(rect.Right - width, rect.Y, width, rect.Height); 22 | } 23 | 24 | public static Matrix GetInvertedMatrix(this Matrix src) 25 | { 26 | var dest = src.Clone(); 27 | dest.Invert(); 28 | return dest; 29 | } 30 | 31 | public static Point TransformPoint(this Matrix matrix, Point point) 32 | { 33 | var arr = new Point[] { point }; 34 | matrix.TransformPoints(arr); 35 | return arr.Single(); 36 | } 37 | 38 | public static PointF TransformPoint(this Matrix matrix, PointF point) 39 | { 40 | var arr = new PointF[] { point }; 41 | matrix.TransformPoints(arr); 42 | return arr.Single(); 43 | } 44 | 45 | /// 46 | /// 凸状のポリゴン内に点が含まれているかどうか判定します。 47 | /// 48 | /// 頂点を格納した配列 49 | /// 判定する座標 50 | /// 座標がポリゴン内に含まれていればtrue 51 | /// ref: http://blackpawn.com/texts/pointinpoly/default.html 52 | public static bool ContainsPoint(this PointF[] vertexes, PointF point) 53 | { 54 | bool hitTriangle(PointF a, PointF b, PointF c, PointF p) 55 | { 56 | var ab = b.Subtract(a); 57 | var ac = c.Subtract(a); 58 | var ap = p.Subtract(a); 59 | 60 | float abab = ab.Dot(ab); 61 | float acac = ac.Dot(ac); 62 | float acap = ac.Dot(ap); 63 | float abac = ab.Dot(ac); 64 | float abap = ab.Dot(ap); 65 | 66 | float denom = acac * abab - abac * abac; 67 | 68 | float u = (acac * abap - abac * acap) / denom; 69 | float v = (abab * acap - abac * abap) / denom; 70 | 71 | return u >= 0 && v >= 0 && u + v < 1; 72 | } 73 | 74 | for (int i = 1; i <= vertexes.Length - 2; i++) 75 | { 76 | if (hitTriangle(vertexes[0], vertexes[i], vertexes[i + 1], point)) return true; 77 | } 78 | 79 | return false; 80 | } 81 | 82 | public static PointF Subtract(this PointF point, PointF offset) 83 | { 84 | return new PointF(point.X - offset.X, point.Y - offset.Y); 85 | } 86 | 87 | public static float Dot(this PointF point, PointF other) 88 | { 89 | return point.X * other.X + point.Y * other.Y; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Ched/UI/ShiftTimeSelectionForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | using Ched.Plugins; 12 | 13 | namespace Ched.UI 14 | { 15 | public partial class ShiftTimeSelectionForm : Form 16 | { 17 | private static readonly IReadOnlyList<(ShiftEvent.DurationType Type, string Text)> DurationTypes = new List<(ShiftEvent.DurationType, string)>() 18 | { 19 | (ShiftEvent.DurationType.Bar, "小節"), 20 | (ShiftEvent.DurationType.Beat, "拍") 21 | }; 22 | 23 | public int CountValue => (int)countBox.Value; 24 | 25 | public ShiftEvent.DurationType DurationType => DurationTypes[durationTypeBox.SelectedIndex].Type; 26 | 27 | public ShiftTimeSelectionForm() 28 | { 29 | InitializeComponent(); 30 | AcceptButton = buttonOK; 31 | CancelButton = buttonCancel; 32 | buttonOK.DialogResult = DialogResult.OK; 33 | buttonCancel.DialogResult = DialogResult.Cancel; 34 | 35 | countBox.Minimum = -10000; 36 | countBox.Maximum = 10000; 37 | countBox.Value = 1; 38 | durationTypeBox.DropDownStyle = ComboBoxStyle.DropDownList; 39 | durationTypeBox.Items.AddRange(DurationTypes.Select(p => p.Text).ToArray()); 40 | durationTypeBox.SelectedIndex = 0; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Ched/UI/Shortcuts/Commands.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ched.UI.Shortcuts 8 | { 9 | public static class Commands 10 | { 11 | // MenuStrip 12 | public static string NewFile => "files.new"; 13 | public static string OpenFile => "files.open"; 14 | public static string Save => "files.save"; 15 | public static string SaveAs => "files.saveAs"; 16 | public static string ReExport => "files.reExport"; 17 | public static string ShowScoreBookProperties => "editor.action.showScoreBookProperties"; 18 | public static string ShowShortcutSettings => "application.showShortcutSettings"; 19 | 20 | public static string Undo => "editor.action.undo"; 21 | public static string Redo => "editor.action.redo"; 22 | 23 | public static string Cut => "editor.action.clipboardCut"; 24 | public static string Copy => "editor.action.clipboardCopy"; 25 | public static string Paste => "editor.action.clipboardPaste"; 26 | public static string PasteFlip => "editor.action.clipboardPasteFlip"; 27 | 28 | public static string SelectAll => "editor.action.selectAll"; 29 | public static string SelectToBegin => "editor.action.selectToBegin"; 30 | public static string SelectToEnd => "editor.action.selectToEnd"; 31 | 32 | public static string FlipSelectedNotes => "editor.action.flipSelectedNotes"; 33 | public static string RemoveSelectedNotes => "editor.action.removeSelectedNotes"; 34 | public static string RemoveSelectedEvents => "editor.action.removeSelectedEvents"; 35 | 36 | public static string SwitchScorePreviewMode => "editor.view.switchScorePreviewMode"; 37 | 38 | public static string WidenLaneWidth => "editor.view.widenLaneWidth"; 39 | public static string NarrowLaneWidth => "editor.view.narrowLaneWidth"; 40 | 41 | public static string InsertBpmChange => "editor.action.insertBpmChange"; 42 | public static string InsertTimeSignatureChange => "editor.action.insertTimeSignatureChange"; 43 | public static string InsertHighSpeedChange => "editor.action.insertHighSpeedChange"; 44 | 45 | public static string PlayPreview => "editor.view.playPreview"; 46 | 47 | public static string ShowHelp => "application.showHelp"; 48 | 49 | // ToolStrip 50 | public static string SelectPen => "editor.selectPen"; 51 | public static string SelectSelection => "editor.selectSelection"; 52 | public static string SelectEraser => "editor.selectEraser"; 53 | 54 | public static string ZoomIn => "editor.view.zoomIn"; 55 | public static string ZoomOut => "editor.view.zoomOut"; 56 | 57 | public static string SelectTap => "editor.selectTap"; 58 | public static string SelectExTap => "editor.selectExTap"; 59 | public static string SelectHold => "editor.selectHold"; 60 | public static string SelectSlide => "editor.selectSlide"; 61 | public static string SelectSlideStep => "editor.selectSlideStep"; 62 | public static string SelectAir => "editor.selectAir"; 63 | public static string SelectAirUp => "editor.selectAirUp"; 64 | public static string SelectAirDown => "editor.selectAirDown"; 65 | public static string SelectAirAction => "editor.selectAirAction"; 66 | public static string SelectFlick => "editor.selectFlick"; 67 | public static string SelectDamage => "editor.selectDamage"; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Ched/UI/Shortcuts/KeyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace Ched.UI.Shortcuts 10 | { 11 | public static class ShortcutExtensions 12 | { 13 | public static string ToShortcutChar(this Keys key) => key.ToShortcutString(key.IsMapRequired()); 14 | public static string ToShortcutKey(this Keys key) => key.ToShortcutString(false); 15 | 16 | private static string ToShortcutString(this Keys key, bool toChar) 17 | { 18 | IEnumerable Build() 19 | { 20 | if (key.HasFlag(Keys.Control)) yield return "Ctrl"; 21 | if (key.HasFlag(Keys.Shift)) yield return "Shift"; 22 | if (key.HasFlag(Keys.Alt)) yield return "Alt"; 23 | 24 | var keyCode = key & Keys.KeyCode; 25 | switch (keyCode) 26 | { 27 | case Keys.None: 28 | case Keys.ControlKey: 29 | case Keys.ShiftKey: 30 | yield break; 31 | } 32 | 33 | yield return toChar ? keyCode.ToChar().ToString() : keyCode.ToString(); 34 | } 35 | 36 | return string.Join("+", Build()); 37 | } 38 | 39 | private static bool IsMapRequired(this Keys key) 40 | { 41 | var keyCode = key & Keys.KeyCode; 42 | 43 | if (keyCode >= Keys.D0 && keyCode <= Keys.D9) return true; 44 | if ((int)keyCode >= 0xba && (int)keyCode <= 0xe2) return true; // Oem key 45 | 46 | return false; 47 | } 48 | } 49 | 50 | // https://stackoverflow.com/questions/318777/c-sharp-how-to-translate-virtual-keycode-to-char 51 | internal static class NativeMethods 52 | { 53 | [DllImport("user32.dll")] 54 | private static extern int MapVirtualKey(uint uCode, uint uMapType); 55 | 56 | public static char ToChar(this Keys key) 57 | { 58 | // Convert with MAPVK_VK_TO_CHAR 59 | return Convert.ToChar(MapVirtualKey((uint)key, 2)); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Ched/UI/Shortcuts/ShortcutCommandSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | namespace Ched.UI.Shortcuts 9 | { 10 | public interface IShortcutCommandSource 11 | { 12 | IEnumerable Commands { get; } 13 | 14 | /// 15 | /// 指定のコマンドを実行します。 16 | /// 17 | /// 実行するコマンド 18 | /// コマンドが実行された場合はTrue 19 | bool ExecuteCommand(string command); 20 | 21 | bool ResolveCommandName(string command, out string name); 22 | } 23 | 24 | public class NullShortcutCommandSource : IShortcutCommandSource 25 | { 26 | public IEnumerable Commands => Enumerable.Empty(); 27 | 28 | // Do nothing 29 | public bool ExecuteCommand(string command) => false; 30 | 31 | public bool ResolveCommandName(string command, out string name) 32 | { 33 | name = null; 34 | return false; 35 | } 36 | } 37 | 38 | public class ShortcutCommandSource : IShortcutCommandSource 39 | { 40 | private Dictionary commands { get; } = new Dictionary(); 41 | 42 | public IEnumerable Commands => commands.Keys; 43 | 44 | public void RegisterCommand(string command, string name, Action action) 45 | { 46 | if (commands.ContainsKey(command)) throw new InvalidOperationException("The command is already registered."); 47 | commands.Add(command, (name, action)); 48 | } 49 | 50 | public bool ExecuteCommand(string command) 51 | { 52 | if (!commands.ContainsKey(command)) return false; 53 | commands[command].Action(); 54 | return true; 55 | } 56 | 57 | public bool ResolveCommandName(string command, out string name) 58 | { 59 | name = null; 60 | if (!commands.ContainsKey(command)) return false; 61 | name = commands[command].Name; 62 | return true; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Ched/UI/Shortcuts/ShortcutManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | namespace Ched.UI.Shortcuts 9 | { 10 | public class ShortcutManager 11 | { 12 | public event EventHandler ShortcutUpdated; 13 | 14 | public IShortcutCommandSource CommandSource { get; set; } = new NullShortcutCommandSource(); 15 | public IShortcutKeySource DefaultKeySource { get; set; } = new NullShortcutKeySource(); 16 | public IShortcutKeySource UserKeySource { get; set; } = new NullShortcutKeySource(); 17 | 18 | public bool ExecuteCommand(Keys key) 19 | { 20 | bool Resolve(IShortcutKeySource source) 21 | { 22 | if (source.ResolveCommand(key, out string command)) 23 | { 24 | return CommandSource.ExecuteCommand(command); 25 | } 26 | return false; 27 | } 28 | 29 | // User, Defaultの順にトラバースしてひっかける 30 | return Resolve(UserKeySource) || Resolve(DefaultKeySource); 31 | } 32 | 33 | public bool ResolveShortcutKey(string command, out Keys key) 34 | { 35 | return UserKeySource.ResolveShortcutKey(command, out key) || DefaultKeySource.ResolveShortcutKey(command, out key); 36 | } 37 | 38 | public void NotifyUpdateShortcut() => ShortcutUpdated?.Invoke(this, EventArgs.Empty); 39 | } 40 | 41 | public class ShortcutManagerHost 42 | { 43 | private ShortcutManager shortcutManager; 44 | private UserShortcutKeySource userShortcutKeySource; 45 | 46 | public ShortcutManager ShortcutManager => shortcutManager; 47 | 48 | public UserShortcutKeySource UserShortcutKeySource 49 | { 50 | get => userShortcutKeySource; 51 | set 52 | { 53 | userShortcutKeySource = value; 54 | ShortcutManager.UserKeySource = value; 55 | ShortcutManager.NotifyUpdateShortcut(); 56 | } 57 | } 58 | 59 | public ShortcutManagerHost(ShortcutManager shortcutManager) 60 | { 61 | this.shortcutManager = shortcutManager; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Ched/UI/Shortcuts/ToolStripItemBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace Ched.UI.Shortcuts 10 | { 11 | internal abstract class ToolStripItemBuilder 12 | { 13 | private Dictionary items = new Dictionary(); 14 | protected ShortcutManager ShortcutManager { get; } 15 | 16 | public ToolStripItemBuilder(ShortcutManager shortcutManager) 17 | { 18 | ShortcutManager = shortcutManager; 19 | ShortcutManager.ShortcutUpdated += OnShortcutUpdated; 20 | } 21 | 22 | private void OnShortcutUpdated(object sender, EventArgs e) 23 | { 24 | var shortcutManager = (ShortcutManager)sender; 25 | foreach (var item in items) 26 | { 27 | if (shortcutManager.ResolveShortcutKey(item.Key, out Keys key)) 28 | { 29 | UpdateShortcutKey(item.Value, key.ToShortcutChar()); 30 | continue; 31 | } 32 | UpdateShortcutKey(item.Value, ""); 33 | } 34 | } 35 | 36 | public T BuildItem(string command, string commandName) => BuildItem(command, commandName, null); 37 | 38 | public T BuildItem(string command, string commandName, Image image) 39 | { 40 | var item = BuildItemInstance(command, commandName, image); 41 | items.Add(command, item); 42 | return item; 43 | } 44 | 45 | protected abstract T BuildItemInstance(string command, string commandName, Image image); 46 | protected abstract void UpdateShortcutKey(T item, string keyText); 47 | } 48 | 49 | internal class ToolStripMenuItemBuilder : ToolStripItemBuilder 50 | { 51 | public ToolStripMenuItemBuilder(ShortcutManager shortcutManager) : base(shortcutManager) 52 | { 53 | } 54 | 55 | protected override ToolStripMenuItem BuildItemInstance(string command, string commandName, Image image) 56 | { 57 | return new ToolStripMenuItem(commandName, null, (s, e) => ShortcutManager.CommandSource.ExecuteCommand(command)); 58 | } 59 | 60 | protected override void UpdateShortcutKey(ToolStripMenuItem item, string keyText) 61 | { 62 | item.ShortcutKeyDisplayString = keyText; 63 | } 64 | } 65 | 66 | internal class ToolStripButtonBuilder : ToolStripItemBuilder 67 | { 68 | private Dictionary commandNameMap = new Dictionary(); 69 | 70 | public ToolStripButtonBuilder(ShortcutManager shortcutManager) : base(shortcutManager) 71 | { 72 | } 73 | 74 | protected override ToolStripButton BuildItemInstance(string command, string commandName, Image image) 75 | { 76 | var button = new ToolStripButton(commandName, image, (s, e) => ShortcutManager.CommandSource.ExecuteCommand(command)) 77 | { 78 | DisplayStyle = ToolStripItemDisplayStyle.Image 79 | }; 80 | commandNameMap.Add(button, commandName); 81 | return button; 82 | } 83 | 84 | protected override void UpdateShortcutKey(ToolStripButton item, string keyText) 85 | { 86 | string commandName = commandNameMap[item]; 87 | item.Text = string.IsNullOrEmpty(keyText) ? commandName : $"{commandName} ({keyText})"; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Ched/UI/TimeSignatureSelectionForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Ched.UI 2 | { 3 | partial class TimeSignatureSelectionForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TimeSignatureSelectionForm)); 32 | this.numeratorBox = new System.Windows.Forms.ComboBox(); 33 | this.denominatorBox = new System.Windows.Forms.ComboBox(); 34 | this.buttonOK = new System.Windows.Forms.Button(); 35 | this.buttonCancel = new System.Windows.Forms.Button(); 36 | this.label1 = new System.Windows.Forms.Label(); 37 | this.SuspendLayout(); 38 | // 39 | // numeratorBox 40 | // 41 | this.numeratorBox.FormattingEnabled = true; 42 | resources.ApplyResources(this.numeratorBox, "numeratorBox"); 43 | this.numeratorBox.Name = "numeratorBox"; 44 | // 45 | // denominatorBox 46 | // 47 | this.denominatorBox.FormattingEnabled = true; 48 | resources.ApplyResources(this.denominatorBox, "denominatorBox"); 49 | this.denominatorBox.Name = "denominatorBox"; 50 | // 51 | // buttonOK 52 | // 53 | resources.ApplyResources(this.buttonOK, "buttonOK"); 54 | this.buttonOK.Name = "buttonOK"; 55 | this.buttonOK.UseVisualStyleBackColor = true; 56 | // 57 | // buttonCancel 58 | // 59 | resources.ApplyResources(this.buttonCancel, "buttonCancel"); 60 | this.buttonCancel.Name = "buttonCancel"; 61 | this.buttonCancel.UseVisualStyleBackColor = true; 62 | // 63 | // label1 64 | // 65 | resources.ApplyResources(this.label1, "label1"); 66 | this.label1.Name = "label1"; 67 | // 68 | // TimeSignatureSelectionForm 69 | // 70 | resources.ApplyResources(this, "$this"); 71 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 72 | this.Controls.Add(this.label1); 73 | this.Controls.Add(this.buttonCancel); 74 | this.Controls.Add(this.buttonOK); 75 | this.Controls.Add(this.denominatorBox); 76 | this.Controls.Add(this.numeratorBox); 77 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 78 | this.MaximizeBox = false; 79 | this.MinimizeBox = false; 80 | this.Name = "TimeSignatureSelectionForm"; 81 | this.ResumeLayout(false); 82 | this.PerformLayout(); 83 | 84 | } 85 | 86 | #endregion 87 | 88 | private System.Windows.Forms.ComboBox numeratorBox; 89 | private System.Windows.Forms.ComboBox denominatorBox; 90 | private System.Windows.Forms.Button buttonOK; 91 | private System.Windows.Forms.Button buttonCancel; 92 | private System.Windows.Forms.Label label1; 93 | } 94 | } -------------------------------------------------------------------------------- /Ched/UI/TimeSignatureSelectionForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Ched.UI 12 | { 13 | public partial class TimeSignatureSelectionForm : Form 14 | { 15 | public int Numerator 16 | { 17 | get { return numeratorBox.SelectedIndex + 1; } 18 | } 19 | 20 | public int DenominatorExponent 21 | { 22 | get { return denominatorBox.SelectedIndex + 1; } 23 | } 24 | 25 | public TimeSignatureSelectionForm() 26 | { 27 | InitializeComponent(); 28 | AcceptButton = buttonOK; 29 | CancelButton = buttonCancel; 30 | buttonOK.DialogResult = DialogResult.OK; 31 | buttonCancel.DialogResult = DialogResult.Cancel; 32 | 33 | numeratorBox.DropDownStyle = ComboBoxStyle.DropDownList; 34 | denominatorBox.DropDownStyle = ComboBoxStyle.DropDownList; 35 | numeratorBox.Items.AddRange(Enumerable.Range(1, 32).Select(p => p.ToString()).ToArray()); 36 | denominatorBox.Items.AddRange(Enumerable.Range(1, 6).Select(p => Math.Pow(2, p).ToString()).ToArray()); 37 | numeratorBox.SelectedIndex = 4 - 1; 38 | denominatorBox.SelectedIndex = 2 - 1; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Ched/UI/VersionInfoForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Ched.UI 2 | { 3 | partial class VersionInfoForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VersionInfoForm)); 32 | this.pictureBox1 = new System.Windows.Forms.PictureBox(); 33 | this.labelTitle = new System.Windows.Forms.Label(); 34 | this.labelVersion = new System.Windows.Forms.Label(); 35 | this.labelProduct = new System.Windows.Forms.Label(); 36 | this.buttonClose = new System.Windows.Forms.Button(); 37 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 38 | this.SuspendLayout(); 39 | // 40 | // pictureBox1 41 | // 42 | resources.ApplyResources(this.pictureBox1, "pictureBox1"); 43 | this.pictureBox1.Name = "pictureBox1"; 44 | this.pictureBox1.TabStop = false; 45 | // 46 | // labelTitle 47 | // 48 | resources.ApplyResources(this.labelTitle, "labelTitle"); 49 | this.labelTitle.Name = "labelTitle"; 50 | // 51 | // labelVersion 52 | // 53 | resources.ApplyResources(this.labelVersion, "labelVersion"); 54 | this.labelVersion.Name = "labelVersion"; 55 | // 56 | // labelProduct 57 | // 58 | resources.ApplyResources(this.labelProduct, "labelProduct"); 59 | this.labelProduct.Name = "labelProduct"; 60 | // 61 | // buttonClose 62 | // 63 | resources.ApplyResources(this.buttonClose, "buttonClose"); 64 | this.buttonClose.Name = "buttonClose"; 65 | this.buttonClose.UseVisualStyleBackColor = true; 66 | // 67 | // VersionInfoForm 68 | // 69 | resources.ApplyResources(this, "$this"); 70 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 71 | this.Controls.Add(this.buttonClose); 72 | this.Controls.Add(this.labelProduct); 73 | this.Controls.Add(this.labelVersion); 74 | this.Controls.Add(this.labelTitle); 75 | this.Controls.Add(this.pictureBox1); 76 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 77 | this.MaximizeBox = false; 78 | this.MinimizeBox = false; 79 | this.Name = "VersionInfoForm"; 80 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 81 | this.ResumeLayout(false); 82 | this.PerformLayout(); 83 | 84 | } 85 | 86 | #endregion 87 | 88 | private System.Windows.Forms.PictureBox pictureBox1; 89 | private System.Windows.Forms.Label labelTitle; 90 | private System.Windows.Forms.Label labelVersion; 91 | private System.Windows.Forms.Label labelProduct; 92 | private System.Windows.Forms.Button buttonClose; 93 | } 94 | } -------------------------------------------------------------------------------- /Ched/UI/VersionInfoForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using System.Reflection; 11 | using Ched.Properties; 12 | 13 | namespace Ched.UI 14 | { 15 | public partial class VersionInfoForm : Form 16 | { 17 | public VersionInfoForm() 18 | { 19 | InitializeComponent(); 20 | 21 | var asm = Assembly.GetEntryAssembly(); 22 | 23 | labelTitle.Text = string.Format("{0} - {1}", asm.GetCustomAttribute().Title, asm.GetCustomAttribute().Description); 24 | labelVersion.Text = string.Format("Version {0}", asm.GetName().Version.ToString()); 25 | labelProduct.Text = asm.GetCustomAttribute().Copyright; 26 | 27 | pictureBox1.Image = Bitmap.FromHicon(Resources.MainIcon.Handle); 28 | 29 | buttonClose.Click += (s, e) => Close(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Ched/UI/Windows/Behaviors/HideWindowCloseButtonBehavior.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Interop; 9 | using Microsoft.Xaml.Behaviors; 10 | 11 | namespace Ched.UI.Windows.Behaviors 12 | { 13 | public class HideWindowCloseButtonBehavior : Behavior 14 | { 15 | #region NativeMethods 16 | private const int GWL_STYLE = -16; 17 | private const int WS_SYSMENU = 0x80000; 18 | 19 | [DllImport("user32.dll", SetLastError = true)] 20 | private static extern int GetWindowLong(IntPtr hWnd, int nIndex); 21 | 22 | [DllImport("user32.dll")] 23 | private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); 24 | #endregion 25 | 26 | protected override void OnAttached() 27 | { 28 | base.OnAttached(); 29 | AssociatedObject.Loaded += OnLoaded; 30 | } 31 | 32 | protected override void OnDetaching() 33 | { 34 | AssociatedObject.Loaded -= OnLoaded; 35 | base.OnDetaching(); 36 | } 37 | 38 | private void OnLoaded(object sender, RoutedEventArgs e) 39 | { 40 | var hwnd = new WindowInteropHelper(AssociatedObject).Handle; 41 | SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Ched/UI/Windows/Behaviors/InitialFocusBehavior.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Input; 8 | using Microsoft.Xaml.Behaviors; 9 | 10 | namespace Ched.UI.Windows.Behaviors 11 | { 12 | public class InitialFocusBehavior : Behavior 13 | { 14 | protected override void OnAttached() 15 | { 16 | base.OnAttached(); 17 | AssociatedObject.Loaded += OnLoaded; 18 | } 19 | 20 | protected override void OnDetaching() 21 | { 22 | base.OnDetaching(); 23 | AssociatedObject.Loaded -= OnLoaded; 24 | } 25 | 26 | private void OnLoaded(object sender, RoutedEventArgs e) 27 | { 28 | ((Window)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Ched/UI/Windows/Behaviors/OpenFileBehavior.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Input; 9 | using Microsoft.Xaml.Behaviors; 10 | 11 | namespace Ched.UI.Windows.Behaviors 12 | { 13 | public class OpenFileBehavior : Behavior