diff --git a/ChartUndoCodeData.h b/ChartUndoCodeData.h index 4e54484..e0d83cd 100644 --- a/ChartUndoCodeData.h +++ b/ChartUndoCodeData.h @@ -24,5 +24,6 @@ UCODE_DEF(SECTION_CREATE) UCODE_DEF(SECTION_DELETE) UCODE_DEF(SECTION_PROPS) UCODE_DEF(SONG_PROPS) +UCODE_DEF(MULTI_CHORD_EDIT) #undef UCODE_DEF \ No newline at end of file diff --git a/ChordEase.chm b/ChordEase.chm index ca6fc7d..564138d 100644 Binary files a/ChordEase.chm and b/ChordEase.chm differ diff --git a/ChordEase.cpp b/ChordEase.cpp index 7ff9cb2..fabd35e 100644 --- a/ChordEase.cpp +++ b/ChordEase.cpp @@ -467,6 +467,31 @@ CString CChordEaseApp::GetFileTitle(const CString& Path) return(sTitle); } +void CChordEaseApp::InitNoteCombo(CComboBox& Combo, CIntRange Range, int SelIdx) +{ + CString s; + int iSel = -1; + for (CNote iNote = Range.Start; iNote <= Range.End; iNote++) { + Combo.AddString(iNote.MidiName()); + if (iNote == SelIdx) + iSel = iNote - Range.Start; + } + Combo.SetCurSel(iSel); +} + +void CChordEaseApp::InitNumericCombo(CComboBox& Combo, CIntRange Range, int SelIdx) +{ + CString s; + int iSel = -1; + for (int iItem = Range.Start; iItem <= Range.End; iItem++) { + s.Format(_T("%d"), iItem); + Combo.AddString(s); + if (iItem == SelIdx) + iSel = iItem - Range.Start; + } + Combo.SetCurSel(iSel); +} + ///////////////////////////////////////////////////////////////////////////// // CChordEaseApp message map diff --git a/ChordEase.dsp b/ChordEase.dsp index f9cccdc..7ec3d9d 100644 --- a/ChordEase.dsp +++ b/ChordEase.dsp @@ -548,14 +548,6 @@ SOURCE=.\MidiTargetDlg.h # End Source File # Begin Source File -SOURCE=.\MidiTargetRowDlg.cpp -# End Source File -# Begin Source File - -SOURCE=.\MidiTargetRowDlg.h -# End Source File -# Begin Source File - SOURCE=.\MidiWrap.cpp # End Source File # Begin Source File @@ -808,6 +800,10 @@ SOURCE=.\PartsBar.h # End Source File # Begin Source File +SOURCE=.\PartsListColDef.h +# End Source File +# Begin Source File + SOURCE=.\PartsListCtrl.cpp # End Source File # Begin Source File @@ -832,14 +828,6 @@ SOURCE=.\Patch.h # End Source File # Begin Source File -SOURCE=.\PatchAutoInstDlg.cpp -# End Source File -# Begin Source File - -SOURCE=.\PatchAutoInstDlg.h -# End Source File -# Begin Source File - SOURCE=.\PatchBar.cpp # End Source File # Begin Source File @@ -1040,30 +1028,6 @@ SOURCE=.\Round.h # End Source File # Begin Source File -SOURCE=.\RowDlg.cpp -# End Source File -# Begin Source File - -SOURCE=.\RowDlg.h -# End Source File -# Begin Source File - -SOURCE=.\RowForm.cpp -# End Source File -# Begin Source File - -SOURCE=.\RowForm.h -# End Source File -# Begin Source File - -SOURCE=.\RowView.cpp -# End Source File -# Begin Source File - -SOURCE=.\RowView.h -# End Source File -# Begin Source File - SOURCE=.\SafeHandle.cpp # End Source File # Begin Source File @@ -1325,10 +1289,6 @@ SOURCE=.\Wrapx64.h # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # Begin Source File -SOURCE=.\res\chordeas.ico -# End Source File -# Begin Source File - SOURCE=.\res\ChordEase.ico # End Source File # Begin Source File @@ -1353,30 +1313,10 @@ SOURCE=.\res\dragsingle.cur # End Source File # Begin Source File -SOURCE=.\res\gear.ico -# End Source File -# Begin Source File - SOURCE=.\res\header_sort.bmp # End Source File # Begin Source File -SOURCE=.\res\ico00001.ico -# End Source File -# Begin Source File - -SOURCE=.\res\icon1.ico -# End Source File -# Begin Source File - -SOURCE=.\res\icon2.ico -# End Source File -# Begin Source File - -SOURCE=.\res\rec_play.ico -# End Source File -# Begin Source File - SOURCE=.\res\RecPlayPause.ico # End Source File # Begin Source File diff --git a/ChordEase.h b/ChordEase.h index 18ae663..0a52c61 100644 --- a/ChordEase.h +++ b/ChordEase.h @@ -86,6 +86,8 @@ class CChordEaseApp : public CWinAppCK void MakeAbsolutePath(CString& Path); static void ValidateFolder(CDataExchange* pDX, int CtrlID, const CString& Path); BOOL OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + static void InitNoteCombo(CComboBox& Combo, CIntRange Range, int SelIdx); + static void InitNumericCombo(CComboBox& Combo, CIntRange Range, int SelIdx); // Overrides // ClassWizard generated virtual function overrides diff --git a/ChordEase.rc b/ChordEase.rc index 8c8f11b..db99bf5 100644 --- a/ChordEase.rc +++ b/ChordEase.rc @@ -337,6 +337,15 @@ BEGIN END END +IDM_MIDI_TARGET_CTX MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Learn", ID_MIDI_LEARN + MENUITEM "&Reset", ID_MIDI_TARGET_RESET + END +END + ///////////////////////////////////////////////////////////////////////////// // @@ -440,28 +449,28 @@ STYLE DS_CONTROL | WS_CHILD | WS_CAPTION CAPTION "Metronome" FONT 8, "MS Sans Serif" BEGIN - CONTROL "Enable",IDC_PATCH_AINST_ENABLE,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,7,7,38,10 + CONTROL "Enable",IDC_PATCH_METRO_ENABLE,"Button",BS_AUTOCHECKBOX | + BS_NOTIFY | WS_TABSTOP,7,7,38,10 LTEXT "Port:",IDC_STATIC,7,22,16,8 - EDITTEXT IDC_PATCH_AINST_PORT,7,32,34,12,ES_AUTOHSCROLL + EDITTEXT IDC_PATCH_METRO_PORT,7,32,34,12,ES_AUTOHSCROLL LTEXT "Channel:",IDC_STATIC,45,22,29,8 - EDITTEXT IDC_PATCH_AINST_CHANNEL,45,32,34,12,ES_AUTOHSCROLL + EDITTEXT IDC_PATCH_METRO_CHANNEL,45,32,34,12,ES_AUTOHSCROLL LTEXT "Patch:",IDC_STATIC,83,22,22,8 - EDITTEXT IDC_PATCH_AINST_PATCH,83,32,34,12,ES_AUTOHSCROLL + EDITTEXT IDC_PATCH_METRO_PATCH,83,32,34,12,ES_AUTOHSCROLL LTEXT "Volume:",IDC_STATIC,121,22,26,8 - EDITTEXT IDC_PATCH_AINST_VOLUME,121,32,34,12,ES_AUTOHSCROLL + EDITTEXT IDC_PATCH_METRO_VOLUME,121,32,34,12,ES_AUTOHSCROLL GROUPBOX "Normal",IDC_STATIC,7,50,85,40 LTEXT "Note:",IDC_STATIC,14,60,18,8 EDITTEXT IDC_PATCH_METRO_NOTE,14,70,34,12,ES_AUTOHSCROLL LTEXT "Velocity:",IDC_STATIC,52,60,28,8 - EDITTEXT IDC_PATCH_AINST_VELOCITY,52,70,34,12,ES_AUTOHSCROLL + EDITTEXT IDC_PATCH_METRO_VELOCITY,52,70,34,12,ES_AUTOHSCROLL GROUPBOX "Accent",IDC_STATIC,99,50,85,52 LTEXT "Note:",IDC_STATIC,106,60,18,8 EDITTEXT IDC_PATCH_METRO_ACCENT_NOTE,106,70,34,12,ES_AUTOHSCROLL LTEXT "Velocity:",IDC_STATIC,144,60,28,8 EDITTEXT IDC_PATCH_METRO_ACCENT_VEL,144,70,34,12,ES_AUTOHSCROLL CONTROL "Use same note",IDC_PATCH_METRO_ACCENT_SAME_NOTE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,106,86,63,10 + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,106,86,63,10 END IDD_PART_INPUT DIALOG DISCARDABLE 0, 0, 180, 86 @@ -506,11 +515,11 @@ BEGIN COMBOBOX IDC_PART_OUT_ANTICIPATION,7,47,60,80,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP CONTROL "Controllers thru",IDC_PART_OUT_CONTROLS_THRU,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,77,38,63,10 + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,77,38,63,10 CONTROL "Local control",IDC_PART_OUT_LOCAL_CONTROL,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,77,51,57,10 + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,77,51,57,10 CONTROL "Fix held notes",IDC_PART_OUT_FIX_HELD_NOTES,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,67,62,10 + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,7,67,62,10 LTEXT "Device:",IDC_STATIC,7,83,26,12 EDITTEXT IDC_PART_OUT_DEVICE_NAME,35,83,138,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP @@ -525,7 +534,7 @@ BEGIN LTEXT "Generic interval:",IDC_STATIC,14,18,52,8 EDITTEXT IDC_PART_LEAD_HARM_INTERVAL,14,28,34,12,ES_AUTOHSCROLL CONTROL "Omit melody",IDC_PART_LEAD_HARM_OMIT_MELODY,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,14,46,54,10 + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,14,46,54,10 GROUPBOX "Static harmony range",IDC_STATIC,73,16,88,41 LTEXT "Minimum:",IDC_STATIC,81,27,30,8 EDITTEXT IDC_PART_LEAD_HARM_STATIC_MIN,81,37,34,12,ES_AUTOHSCROLL @@ -547,7 +556,7 @@ BEGIN WS_VSCROLL | WS_TABSTOP CONTROL "Chord change resets alternation", IDC_PART_COMP_CHORD_RESETS_ALT,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,7,36,116,10 + BS_NOTIFY | WS_TABSTOP,7,36,116,10 GROUPBOX "Arpeggio",IDC_STATIC,7,50,130,55 LTEXT "Period:",IDC_STATIC,14,61,23,8 COMBOBOX IDC_PART_COMP_ARP_PERIOD,14,71,48,80,CBS_DROPDOWN | @@ -556,7 +565,7 @@ BEGIN COMBOBOX IDC_PART_COMP_ARP_ORDER,67,71,64,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Repeat",IDC_PART_COMP_ARP_REPEAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,14,89,39,10 + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,14,89,39,10 END IDD_PART_BASS DIALOG DISCARDABLE 0, 0, 180, 90 @@ -567,7 +576,7 @@ BEGIN LTEXT "Lowest note:",IDC_STATIC,7,7,42,8 EDITTEXT IDC_PART_BASS_LOWEST,7,17,34,12,ES_AUTOHSCROLL CONTROL "Slash chords",IDC_PART_BASS_SLASH_CHORDS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,58,19,57,10 + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,58,19,57,10 LTEXT "Approach length:",IDC_STATIC,7,37,55,8 COMBOBOX IDC_PART_BASS_APPROACH_LENGTH,7,47,60,80,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP @@ -614,13 +623,6 @@ BEGIN PUSHBUTTON "&Default Font",IDC_OPT_CHART_DEFAULT_FONT,64,47,60,14 END -IDD_ROW_FORM DIALOGEX 0, 0, 240, 137 -STYLE WS_CHILD | WS_CLIPCHILDREN -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN -END - IDD_PART_MIDI DIALOG DISCARDABLE 0, 0, 180, 90 STYLE DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION CAPTION "MIDI" @@ -628,21 +630,6 @@ FONT 8, "MS Sans Serif" BEGIN END -IDD_MIDI_TARGET_ROW DIALOG DISCARDABLE 0, 0, 270, 14 -STYLE DS_CONTROL | WS_CHILD -FONT 8, "MS Sans Serif" -BEGIN - LTEXT "",IDS_MIDI_TARG_ROW_NAME,2,0,60,12,SS_NOTIFY | - SS_CENTERIMAGE | SS_ENDELLIPSIS - EDITTEXT IDS_MIDI_TARG_ROW_PORT,64,0,30,12,ES_AUTOHSCROLL - EDITTEXT IDS_MIDI_TARG_ROW_CHAN,96,0,30,12,ES_AUTOHSCROLL - COMBOBOX IDS_MIDI_TARG_ROW_EVENT,128,0,40,60,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - EDITTEXT IDS_MIDI_TARG_ROW_CONTROL,170,0,34,12,ES_AUTOHSCROLL - EDITTEXT IDS_MIDI_TARG_ROW_RANGE_START,206,0,30,12,ES_AUTOHSCROLL - EDITTEXT IDS_MIDI_TARG_ROW_RANGE_END,238,0,30,12,ES_AUTOHSCROLL -END - IDD_MIDI_ASSIGNS DIALOG DISCARDABLE 0, 0, 382, 150 STYLE WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "MIDI Assignments" @@ -681,7 +668,7 @@ CAPTION "Auto" FONT 8, "MS Sans Serif" BEGIN CONTROL "Auto Play",IDC_PART_AUTO_PLAY,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,7,7,46,10 + BS_NOTIFY | WS_TABSTOP,7,7,46,10 LTEXT "Window:",IDC_STATIC,7,22,29,8 EDITTEXT IDC_PART_AUTO_WINDOW,7,32,34,12,ES_AUTOHSCROLL LTEXT "Velocity:",IDC_STATIC,45,22,28,8 @@ -1154,21 +1141,6 @@ BEGIN 0 END -IDD_MIDI_TARGET_ROW DLGINIT -BEGIN - IDS_MIDI_TARG_ROW_EVENT, 0x403, 5, 0 -0x6f4e, 0x656e, "\000" - IDS_MIDI_TARG_ROW_EVENT, 0x403, 8, 0 -0x6f43, 0x746e, 0x6f72, 0x006c, - IDS_MIDI_TARG_ROW_EVENT, 0x403, 6, 0 -0x6857, 0x6565, 0x006c, - IDS_MIDI_TARG_ROW_EVENT, 0x403, 15, 0 -0x7250, 0x676f, 0x6172, 0x206d, 0x6843, 0x6e61, 0x6567, "\000" - IDS_MIDI_TARG_ROW_EVENT, 0x403, 16, 0 -0x6843, 0x6e61, 0x4120, 0x7466, 0x7265, 0x6f74, 0x6375, 0x0068, - 0 -END - IDD_PART_INPUT DLGINIT BEGIN IDC_PART_IN_NON_DIATONIC, 0x403, 6, 0 @@ -1194,6 +1166,68 @@ BEGIN IDR_CHORDEASEPATCH "Patch\n\nPatch\nPatch Files (*.cep)\n.cep\nChordEasePatch.Document\nChordEase Patch" END +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDS_PART_MT_IN_VEL_OFFSET "Input Vel. Offset" + IDS_PART_MT_IN_ZONE_HIGH "Input Zone High" + IDS_PART_MT_IN_ZONE_LOW "Input Zone Low" + IDS_PART_MT_LEAD_HARM_INTERVAL "Lead Harm Interval" + IDS_PART_MT_LEAD_HARM_OMIT_MELODY "Lead Harm Omit Melody" + IDS_PART_MT_LEAD_HARM_STATIC_MAX "Lead Harm Static Max" + IDS_PART_MT_LEAD_HARM_STATIC_MIN "Lead Harm Static Min" + IDS_PART_MT_OUT_ANTICIPATION "Output Harm. Anticipation" + IDS_PART_MT_OUT_FIX_HELD_NOTES "Output Fix Held Notes" + IDS_PART_MT_OUT_PATCH "Output Patch" + IDS_PART_MT_OUT_VOLUME "Output Volume" + IDS_PATCH_BAD_FORMAT "'%1' has an invalid format." + IDS_PATCH_BAR "Patch" + IDS_PATCH_MT_LEAD_IN "Lead-in" + IDS_PATCH_MT_METRO_ENABLE "Metro. Enable" + IDS_PATCH_MT_METRO_VOLUME "Metro. Volume" +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDS_PATCH_MT_NEXT_CHORD "Next Chord" + IDS_PATCH_MT_NEXT_SECTION "Next Section" + IDS_PATCH_MT_PAUSE "Pause" + IDS_PATCH_MT_PLAY "Play" + IDS_PATCH_MT_PREV_CHORD "Previous Chord" + IDS_PATCH_MT_REPEAT "Repeat" + IDS_PATCH_MT_REWIND "Rewind" + IDS_PATCH_MT_SONG_POSITION "Song Position" + IDS_PATCH_MT_TEMPO "Tempo" + IDS_PATCH_MT_TEMPO_MULTIPLE "Tempo Multiple" + IDS_PATCH_MT_TRANSPOSE "Transpose" + IDS_RECORD_AS "Record As" + IDS_RECORD_LOCKED "Locked to always record." + IDS_REC_PLAY_COL_CHANNEL "Chan" + IDS_REC_PLAY_COL_DEVICE "Device" + IDS_REC_PLAY_COL_EVENTS "Events" +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDS_REC_PLAY_COL_NAME "Name" + IDS_REC_PLAY_COL_PORT "Port" + IDS_REC_PLAY_STOP_PLAYING + "Can't do record playback while song is playing. Stop playing?" + IDS_REC_PLAY_STOP_RECORDING + "Can't do record playback while recording. Stop recording?" + IDS_SECTION_NAME_SPACES "Section name can't contain spaces." + IDS_SEC_LIST_COL_IMPLICIT "Implicit" + IDS_SEC_LIST_COL_INDEX "#" + IDS_SEC_LIST_COL_LENGTH "Length" + IDS_SEC_LIST_COL_NAME "Name" + IDS_SEC_LIST_COL_REPEAT "Repeat" + IDS_SEC_LIST_COL_START "Start" + IDS_SONG_ERR_BAD_BASS_NOTE "Invalid bass note in '%s'." + IDS_SONG_ERR_BAD_CHORD "Invalid chord '%s'." + IDS_SONG_ERR_BAD_CHORD_TYPE "Unknown chord type in '%s'." + IDS_SONG_ERR_BAD_COMMAND "Unknown command '%s' or missing duration." + IDS_SONG_ERR_BAD_DURATION "Invalid duration '%d'." +END + STRINGTABLE PRELOAD DISCARDABLE BEGIN ID_APP_CHECK_FOR_UPDATES "Check for a newer version\nCheck for Updates" @@ -1235,6 +1269,7 @@ STRINGTABLE PRELOAD DISCARDABLE BEGIN ID_MIDI_PANIC "Reset all MIDI notes\nPanic" ID_MIDI_RESET_ALL "Reset all MIDI targets\nReset All Targets" + ID_MIDI_TARGET_RESET "Reset MIDI target assignment to default state" ID_OUT_NOTES_ROTATE_LABELS "Rotate key labels sideways" ID_OUT_NOTES_SHOW_KEY_LABELS "Show note names on keys" ID_OUT_NOTES_SHOW_METRONOME "Show metronome notes" @@ -1248,11 +1283,11 @@ BEGIN ID_PATCH_SAVE_AS "Save the current patch with a new name\nSave Patch As" ID_PIANO_KEY_LABEL_TYPE "Hide piano key labels" ID_PIANO_KEY_LABEL_TYPE2 "Show shortcuts on piano keys" - ID_PIANO_KEY_LABEL_TYPE3 "Show input notes on piano keys" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + ID_PIANO_KEY_LABEL_TYPE3 "Show input notes on piano keys" ID_PIANO_KEY_LABEL_TYPE4 "Show output notes on piano keys" ID_PIANO_KEY_LABEL_TYPE5 "Show intervals above root on piano keys" ID_PIANO_KEY_LABEL_TYPE6 "Show scale tones on piano keys" @@ -1269,11 +1304,11 @@ BEGIN ID_TRANSPORT_RECORD "Record performance\nRecord" ID_TRANSPORT_REPEAT "Repeat song\nRepeat" ID_TRANSPORT_REWIND "Rewind to start of song\nRewind" - ID_VIEW_OUTPUT_NOTES "Show or hide the output notes bar\nToggle Output Notes" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + ID_VIEW_OUTPUT_NOTES "Show or hide the output notes bar\nToggle Output Notes" ID_VIEW_PARTS "Show or hide the parts bar\nToggle Parts Bar" ID_VIEW_PATCH "Show or hide the patch bar\nToggle Patch Bar" ID_VIEW_PIANO "Show or hide the virtual piano\nToggle Piano" @@ -1292,17 +1327,18 @@ BEGIN IDS_CHART_UC_CUT "Cut Chords" IDS_CHART_UC_DELETE "Delete Chords" IDS_CHART_UC_INSERT "Insert Chords" + IDS_CHART_UC_MULTI_CHORD_EDIT "Chord Edit" IDS_CHART_UC_PASTE "Paste Chords" IDS_CHART_UC_REORDER "Drag Chords" IDS_CHART_UC_SECTION_CREATE "Create Section" IDS_CHART_UC_SECTION_DELETE "Delete Section" IDS_CHART_UC_SECTION_PROPS "Section Properties" IDS_CHART_UC_SONG_EDIT "Song Text Edit" - IDS_CHART_UC_SONG_PROPS "Song Properties" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_CHART_UC_SONG_PROPS "Song Properties" IDS_CHORD_DURATION_OTHER "&Other..." IDS_CKUP_CANT_GET_ADDR "Can't get address '%1'.\n%2" IDS_CKUP_CANT_LOAD_DLL "Can't load library '%1'.\n%2" @@ -1318,11 +1354,11 @@ BEGIN IDS_DEVICE_STATE_OPEN "Open" IDS_EDIT_REDO_FMT "&Redo %s\tCtrl+Y" IDS_EDIT_UNDO_FMT "&Undo %s\tCtrl+Z" - IDS_ENGERR_CANT_CLOSE_MIDI_IN "Can't close MIDI input device '%s'.\n%s" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_ENGERR_CANT_CLOSE_MIDI_IN "Can't close MIDI input device '%s'.\n%s" IDS_ENGERR_CANT_CLOSE_MIDI_OUT "Can't close MIDI output device '%s'.\n%s" IDS_ENGERR_CANT_OPEN_MIDI_IN "Can't open MIDI input device '%s'.\n%s" IDS_ENGERR_CANT_OPEN_MIDI_OUT "Can't open MIDI output device '%s'.\n%s" @@ -1338,11 +1374,11 @@ BEGIN IDS_ENGERR_START_TIMER_THREAD "Can't start timer thread." IDS_ENGERR_STOP_TIMER_THREAD "Can't stop timer thread." IDS_ENGERR_TOO_MANY_NOTES "Too many notes." - IDS_ENGINE_MIDI_DEVICE_NONE "" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_ENGINE_MIDI_DEVICE_NONE "" IDS_ENGMSG_MISSING_DEVICE "One or more referenced MIDI devices are missing." IDS_HLINK_CANT_LAUNCH "Can't launch browser." @@ -1359,11 +1395,11 @@ BEGIN IDS_MIDI_EVT_COL_CHANNEL "Chan" IDS_MIDI_EVT_COL_DEVICE "Device" IDS_MIDI_EVT_COL_MESSAGE "Message" - IDS_MIDI_EVT_COL_P1 "P1" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_MIDI_EVT_COL_P1 "P1" IDS_MIDI_EVT_COL_P2 "P2" IDS_MIDI_EVT_COL_PORT "Port" IDS_MIDI_EVT_COL_TIMESTAMP "Timestamp" @@ -1379,11 +1415,11 @@ BEGIN IDS_MIDI_NMAP_COL_OUT_DEVICE "Output Device" IDS_MIDI_NMAP_COL_OUT_PORT "Output Port" IDS_MIDI_NMAP_COL_PART_INDEX "#" - IDS_MIDI_NMAP_COL_PART_NAME "Part Name" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_MIDI_NMAP_COL_PART_NAME "Part Name" IDS_MIDI_NMAP_COL_ZONE_HIGH "Zone High" IDS_MIDI_NMAP_COL_ZONE_LOW "Zone Low" IDS_MIDI_OUTPUT_BAR "MIDI Output" @@ -1400,11 +1436,11 @@ BEGIN IDS_MIDI_STAT_EOX "EOX" IDS_MIDI_STAT_KEY_AFT "Key Aft" IDS_MIDI_STAT_MTC_QTR_FRAME "MTC Qtr Frame" - IDS_MIDI_STAT_NOTE_OFF "Note Off" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_MIDI_STAT_NOTE_OFF "Note Off" IDS_MIDI_STAT_NOTE_ON "Note On" IDS_MIDI_STAT_PATCH "Patch" IDS_MIDI_STAT_SONG_POSITION "Song Position" @@ -1416,17 +1452,83 @@ BEGIN IDS_MIDI_STAT_SYSTEM_WILDCARD "System *" IDS_MIDI_STAT_TUNE_REQUEST "Tune Request" IDS_MIDI_STAT_WHEEL "Wheel" - IDS_MIDI_TARG_ROW_CHAN "Input channel number" - IDS_MIDI_TARG_ROW_CONTROL "Input controller number" - IDS_MIDI_TARG_ROW_EVENT "Input event type" - IDS_MIDI_TARG_ROW_NAME "Target parameter name" - IDS_MIDI_TARG_ROW_PORT "MIDI input device index" + IDS_MIDI_TARG_COL_CHAN "Chan" + IDS_MIDI_TARG_COL_CONTROL "Control" + IDS_MIDI_TARG_COL_EVENT "Event" + IDS_MIDI_TARG_COL_NAME "Target" +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDC_MIDI_TARGET_LIST "MIDI target list" + IDC_MIDI_TARG_CHAN "Input channel number" + IDC_MIDI_TARG_CONTROL "Input controller number" + IDC_MIDI_TARG_EVENT "Input event type" + IDC_MIDI_TARG_NAME "Target parameter name" + IDC_MIDI_TARG_PORT "MIDI input device index" + IDC_MIDI_TARG_RANGE_END "End of normalized controller range" + IDC_MIDI_TARG_RANGE_START "Start of normalized controller range" + IDC_MIDI_TARG_VALUE "Current value of MIDI controller" + IDC_OPT_CHART_CHOOSE_FONT "Select chart font" + IDC_OPT_CHART_DEFAULT_FONT "Reset chart font to default" + IDC_OPT_CHART_LINE_MEASURES "Number of measures per line" + IDC_OPT_OTHER_AUTO_CHECK_UPDATES + "Automatically check for updates on startup" +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDC_OPT_OTHER_DATA_FOLDER_BROWSE "Browse for application data folder" + IDC_OPT_OTHER_DATA_FOLDER_PATH "Location of application data folder" + IDC_OPT_OTHER_DATA_FOLDER_TYPE "Use default application data folder" + IDC_OPT_OTHER_DATA_FOLDER_TYPE2 "Specify custom application data folder" + IDC_OPT_OTHER_SHOW_TOOLTIPS "Display tooltips" + IDC_OPT_REC_ALWAYS_RECORD "Always record while playing" + IDC_OPT_REC_BUFFER_SIZE "Size of record buffer size, in events" + IDC_OPT_REC_FOLDER_BROWSE "Browse for destination folder" + IDC_OPT_REC_FOLDER_PATH "Location of destination folder" + IDC_OPT_REC_FOLDER_TYPE "Use default destination folder for recordings" + IDC_OPT_REC_FOLDER_TYPE2 + "Specify custom destination folder for recordings" + IDC_OPT_REC_MIDI_FILE_PPQ + "Time resolution of output MIDI file, in pulses per quarter note" + IDC_OPT_REC_PROMPT_FILENAME + "Prompt for filename before recording; else generate filename" + IDC_PARTS_LIST " " + IDC_PART_AUTO_PLAY "Play part automatically" + IDC_PART_AUTO_VELOCITY "Auto-play note velocity" +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDC_PART_AUTO_WINDOW "Start of auto-play pitch window" + IDC_PART_BASS_APPROACH_LENGTH + "Fixed bass approach length, as fraction of whole note" + IDC_PART_BASS_APPROACH_TRIGGER "Trigger bass approach to target chord" + IDC_PART_BASS_LOWEST "Lowest bass note allowed" + IDC_PART_BASS_SLASH_CHORDS "Respect slash chord bass notes" + IDC_PART_BASS_TARGET_ALIGNMENT + "Alignment of triggered bass approach target, in measures" + IDC_PART_COMP_ARP_ORDER "Arpeggio note order" + IDC_PART_COMP_ARP_PERIOD "Time between arpeggio notes, in whole notes" + IDC_PART_COMP_ARP_PERIOD_QUANT + "Time between arpeggio notes, in quantized units" + IDC_PART_COMP_ARP_REPEAT "True if arpeggio repeats; false for one-shot" + IDC_PART_COMP_CHORD_RESETS_ALT + "True if chord change resets variant alternation" + IDC_PART_COMP_VARIATION "Chord variation scheme" + IDC_PART_COMP_VOICING "Chord voicing type" + IDC_PART_ENABLE "Enable this part" + IDC_PART_FUNCTION "Part mapping function" + IDC_PART_IN_CC_NOTE "Note input via continuous controller" END STRINGTABLE PRELOAD DISCARDABLE BEGIN - IDS_MIDI_TARG_ROW_RANGE_END "End of normalized controller range" - IDS_MIDI_TARG_ROW_RANGE_START "Start of normalized controller range" + IDS_MIDI_TARG_COL_PORT "Port" + IDS_MIDI_TARG_COL_RANGE_END "End" + IDS_MIDI_TARG_COL_RANGE_START "Start" + IDS_MIDI_TARG_COL_VALUE "Value" IDS_MSGBOX_NO "&No" IDS_MSGBOX_YES "&Yes" IDS_MTEVT_CHAN_AFTERTOUCH "Chan Aftertouch" @@ -1439,12 +1541,12 @@ BEGIN IDS_OPT_OTHER_DATA_FOLDER "Application data folder" IDS_OPT_REC_OUTPUT_FOLDER "Record output folder" IDS_OPT_RESET_ALL "Reset All" - IDS_OPT_RESTORE_DEFAULTS "Restore all options to default settings?" - IDS_OUTPUT_NOTES_BAR "Output Notes" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_OPT_RESTORE_DEFAULTS "Restore all options to default settings?" + IDS_OUTPUT_NOTES_BAR "Output Notes" IDS_OUT_NOTES_FILTER_ALL "All" IDS_OUT_NOTES_SM_ALL_CHANS "Show output notes for all channels" IDS_OUT_NOTES_SM_ALL_PORTS "Show output notes for all ports" @@ -1459,12 +1561,12 @@ BEGIN IDS_PART_MT_AUTO_PLAY "Auto Play" IDS_PART_MT_AUTO_VELOCITY "Auto Velocity" IDS_PART_MT_AUTO_WINDOW "Auto Window" - IDS_PART_MT_BASS_APPROACH_LENGTH "Bass Approach Length" - IDS_PART_MT_BASS_APPROACH_TRIGGER "Bass Approach Trigger" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDS_PART_MT_BASS_APPROACH_LENGTH "Bass Approach Length" + IDS_PART_MT_BASS_APPROACH_TRIGGER "Bass Approach Trigger" IDS_PART_MT_BASS_SLASH_CHORDS "Bass Slash Chords" IDS_PART_MT_BASS_TARGET_ALIGNMENT "Bass Target Alignment" IDS_PART_MT_COMP_ARP_ORDER "Comp Arp Order" @@ -1479,56 +1581,31 @@ BEGIN IDS_PART_MT_IN_CC_NOTE_VEL "Input CC Note Velocity" IDS_PART_MT_IN_NON_DIATONIC "Input Non-Diatonic" IDS_PART_MT_IN_TRANSPOSE "Input Transpose" - IDS_PART_MT_IN_VEL_OFFSET "Input Vel. Offset" - IDS_PART_MT_IN_ZONE_HIGH "Input Zone High" END STRINGTABLE PRELOAD DISCARDABLE BEGIN - IDS_PART_MT_IN_ZONE_LOW "Input Zone Low" - IDS_PART_MT_LEAD_HARM_INTERVAL "Lead Harm Interval" - IDS_PART_MT_LEAD_HARM_OMIT_MELODY "Lead Harm Omit Melody" - IDS_PART_MT_LEAD_HARM_STATIC_MAX "Lead Harm Static Max" - IDS_PART_MT_LEAD_HARM_STATIC_MIN "Lead Harm Static Min" - IDS_PART_MT_OUT_ANTICIPATION "Harmonic Anticipation" - IDS_PART_MT_OUT_PATCH "Output Patch" - IDS_PART_MT_OUT_VOLUME "Output Volume" - IDS_PATCH_BAD_FORMAT "'%1' has an invalid format." - IDS_PATCH_BAR "Patch" - IDS_PATCH_MT_LEAD_IN "Lead-in" - IDS_PATCH_MT_METRO_ENABLE "Metro. Enable" - IDS_PATCH_MT_METRO_VOLUME "Metro. Volume" - IDS_PATCH_MT_NEXT_CHORD "Next Chord" - IDS_PATCH_MT_NEXT_SECTION "Next Section" - IDS_PATCH_MT_PAUSE "Pause" + IDS_SONG_ERR_BAD_KEY "Invalid key signature '%s'." + IDS_SONG_ERR_BAD_METER "Invalid time signature %d/%d." + IDS_SONG_ERR_BAD_MODE "Unknown mode '%s'." + IDS_SONG_ERR_BAD_ROOT "Invalid root in '%s'." + IDS_SONG_ERR_BAD_SCALE "Unknown scale '%s'." + IDS_SONG_ERR_BAD_SYNTAX "Invalid syntax." + IDS_SONG_ERR_BAD_TEMPO "Invalid tempo '%s'." + IDS_SONG_ERR_CHORD_TONE_RANGE "Chord tone out of range: '%s'." + IDS_SONG_ERR_DUP_CHORD_TYPE "Duplicate chord type '%s'." + IDS_SONG_ERR_READ "Error reading '%s' at line %d." + IDS_SONG_ERR_SEC_BAD_REPEAT "Invalid section repeat count." + IDS_SONG_ERR_SEC_BAD_SYNTAX "Invalid section syntax." + IDS_SONG_ERR_SEC_CANT_NEST "Sections can't be nested." + IDS_SONG_ERR_SEC_UNTERMINATED "Missing section terminator." + IDS_THREADS_COL_KERNEL_TIME "Kernel" + IDS_THREADS_COL_PRIORITY "Priority" END STRINGTABLE PRELOAD DISCARDABLE BEGIN - IDC_PART_BASS_APPROACH_LENGTH - "Fixed bass approach length, as fraction of whole note" - IDC_PART_BASS_APPROACH_TRIGGER "Trigger bass approach to target chord" - IDC_PART_BASS_LOWEST "Lowest bass note allowed" - IDC_PART_BASS_SLASH_CHORDS "Respect slash chord bass notes" - IDC_PART_BASS_TARGET_ALIGNMENT - "Alignment of triggered bass approach target, in measures" - IDC_PART_COMP_ARP_ORDER "Arpeggio note order" - IDC_PART_COMP_ARP_PERIOD "Time between arpeggio notes, in whole notes" - IDC_PART_COMP_ARP_PERIOD_QUANT - "Time between arpeggio notes, in quantized units" - IDC_PART_COMP_ARP_REPEAT "True if arpeggio repeats; false for one-shot" - IDC_PART_COMP_CHORD_RESETS_ALT - "True if chord change resets variant alternation" - IDC_PART_COMP_VARIATION "Chord variation scheme" - IDC_PART_COMP_VOICING "Chord voicing type" - IDC_PART_ENABLE "Enable this part" - IDC_PART_FUNCTION "Part mapping function" - IDC_PART_IN_CC_NOTE "Note input via continuous controller" IDC_PART_IN_CC_NOTE_VEL "Velocity of note input via continuous controller" -END - -STRINGTABLE PRELOAD DISCARDABLE -BEGIN IDC_PART_IN_CHAN "Input channel number" IDC_PART_IN_DEVICE_NAME "MIDI input device name" IDC_PART_IN_NON_DIATONIC "Handling for non-diatonic input notes" @@ -1548,73 +1625,50 @@ BEGIN IDC_PART_NAME "Part name" IDC_PART_OUT_ANTICIPATION "Harmonic anticipation, as fraction of whole note" - IDC_PART_OUT_CHAN "Output channel number" END STRINGTABLE PRELOAD DISCARDABLE BEGIN - IDS_PATCH_MT_PLAY "Play" - IDS_PATCH_MT_PREV_CHORD "Previous Chord" - IDS_PATCH_MT_REPEAT "Repeat" - IDS_PATCH_MT_REWIND "Rewind" - IDS_PATCH_MT_SONG_POSITION "Song Position" - IDS_PATCH_MT_TEMPO "Tempo" - IDS_PATCH_MT_TEMPO_MULTIPLE "Tempo Multiple" - IDS_PATCH_MT_TRANSPOSE "Transpose" - IDS_RECORD_AS "Record As" - IDS_RECORD_LOCKED "Locked to always record." - IDS_REC_PLAY_COL_CHANNEL "Chan" - IDS_REC_PLAY_COL_DEVICE "Device" - IDS_REC_PLAY_COL_EVENTS "Events" - IDS_REC_PLAY_COL_NAME "Name" - IDS_REC_PLAY_COL_PORT "Port" - IDS_REC_PLAY_STOP_PLAYING - "Can't do record playback while song is playing. Stop playing?" + IDC_PART_OUT_CHAN "Output channel number" + IDC_PART_OUT_CONTROLS_THRU "Pass controllers through to output" + IDC_PART_OUT_DEVICE_NAME "MIDI output device name" + IDC_PART_OUT_FIX_HELD_NOTES "Correct held notes that become non-diatonic" + IDC_PART_OUT_LOCAL_CONTROL "Enable local control" + IDC_PART_OUT_PATCH "Patch number, or -1 if none" + IDC_PART_OUT_PORT "MIDI output device index" + IDC_PART_OUT_VOLUME "Output volume, or -1 if none" + IDC_PATCH_GEN_KEY "Transposed key signature" + IDC_PATCH_GEN_LEAD_IN "Lead-in length, in measures" + IDC_PATCH_GEN_PPQ "Time resolution, in pulses per quarter note" + IDC_PATCH_GEN_TEMPO "Tempo, in beats per minute" + IDC_PATCH_GEN_TEMPO_MULTIPLE "Tempo multiplier" + IDC_PATCH_GEN_TRANSPOSE "Key transposition, in semitones" + IDC_PATCH_METRO_ACCENT_NOTE "Accented metronome note" + IDC_PATCH_METRO_ACCENT_SAME_NOTE "Use same note for accent" END STRINGTABLE PRELOAD DISCARDABLE BEGIN - IDS_REC_PLAY_STOP_RECORDING - "Can't do record playback while recording. Stop recording?" - IDS_SECTION_NAME_SPACES "Section name can't contain spaces." - IDS_SEC_LIST_COL_IMPLICIT "Implicit" - IDS_SEC_LIST_COL_INDEX "#" - IDS_SEC_LIST_COL_LENGTH "Length" - IDS_SEC_LIST_COL_NAME "Name" - IDS_SEC_LIST_COL_REPEAT "Repeat" - IDS_SEC_LIST_COL_START "Start" - IDS_SONG_BAD_METER "Invalid time signature %d/%d." - IDS_SONG_ERR_BAD_BASS_NOTE "Invalid bass note in '%s'." - IDS_SONG_ERR_BAD_CHORD "Invalid chord '%s'." - IDS_SONG_ERR_BAD_CHORD_TYPE "Unknown chord type in '%s'." - IDS_SONG_ERR_BAD_COMMAND "Unknown command '%s' or missing duration." - IDS_SONG_ERR_BAD_DURATION "Invalid duration '%d'." - IDS_SONG_ERR_BAD_KEY "Invalid key signature '%s'." - IDS_SONG_ERR_BAD_MODE "Unknown mode '%s'." + IDC_PATCH_METRO_ACCENT_VEL "Accented note velocity" + IDC_PATCH_METRO_CHANNEL "Output channel number" + IDC_PATCH_METRO_ENABLE "Enable metronome" + IDC_PATCH_METRO_NOTE "Normal metronome note" + IDC_PATCH_METRO_PATCH "Patch number, or -1 if none" + IDC_PATCH_METRO_PORT "MIDI output device index" + IDC_PATCH_METRO_VELOCITY "Note velocity" + IDC_PATCH_METRO_VOLUME "Output volume, or -1 if none" + IDC_PIANO_CHANNEL "Output channel number" + IDC_PIANO_KEY_COUNT "Number of keys" + IDC_PIANO_PORT "MIDI output device index" + IDC_PIANO_START_NOTE "Keyboard's first note" + IDC_PIANO_VELOCITY "Output velocity" END STRINGTABLE PRELOAD DISCARDABLE BEGIN - IDS_SONG_ERR_BAD_ROOT "Invalid root in '%s'." - IDS_SONG_ERR_BAD_SCALE "Unknown scale '%s'." - IDS_SONG_ERR_BAD_SYNTAX "Invalid syntax." - IDS_SONG_ERR_BAD_TEMPO "Invalid tempo '%s'." - IDS_SONG_ERR_CHORD_TONE_RANGE "Chord tone out of range: '%s'." - IDS_SONG_ERR_DUP_CHORD_TYPE "Duplicate chord type '%s'." - IDS_SONG_ERR_READ "Error reading '%s' at line %d." - IDS_SONG_ERR_SEC_BAD_REPEAT "Invalid section repeat count." - IDS_SONG_ERR_SEC_BAD_SYNTAX "Invalid section syntax." - IDS_SONG_ERR_SEC_CANT_NEST "Sections can't be nested." - IDS_SONG_ERR_SEC_UNTERMINATED "Missing section terminator." - IDS_THREADS_COL_KERNEL_TIME "Kernel" - IDS_THREADS_COL_PRIORITY "Priority" IDS_THREADS_COL_THREAD_ID "ID" IDS_THREADS_COL_USER_TIME "User" IDS_UC_BASE_PATCH "Base Patch" -END - -STRINGTABLE PRELOAD DISCARDABLE -BEGIN IDS_UC_CUT "Cut Parts" IDS_UC_DELETE "Delete Parts" IDS_UC_ENABLE_PART "Enable Part" @@ -1642,83 +1696,6 @@ BEGIN IDS_APP_TEMP_FOLDER_NOT_FOUND "Temporary folder '%1' not found." END -STRINGTABLE PRELOAD DISCARDABLE -BEGIN - IDC_MIDI_TARGET "PatchMidiRow" - IDC_MIDI_TARG_COL_CHAN "Chan" - IDC_MIDI_TARG_COL_CONTROL "Control" - IDC_MIDI_TARG_COL_EVENT "Event" - IDC_MIDI_TARG_COL_NAME "Target" - IDC_MIDI_TARG_COL_PORT "Port" - IDC_MIDI_TARG_COL_RANGE_END "End" - IDC_MIDI_TARG_COL_RANGE_START "Start" - IDC_OPT_CHART_CHOOSE_FONT "Select chart font" - IDC_OPT_CHART_DEFAULT_FONT "Reset chart font to default" - IDC_OPT_CHART_LINE_MEASURES "Number of measures per line" - IDC_OPT_OTHER_AUTO_CHECK_UPDATES - "Automatically check for updates on startup" - IDC_OPT_OTHER_DATA_FOLDER_BROWSE "Browse for application data folder" -END - -STRINGTABLE PRELOAD DISCARDABLE -BEGIN - IDC_OPT_OTHER_DATA_FOLDER_PATH "Location of application data folder" - IDC_OPT_OTHER_DATA_FOLDER_TYPE "Use default application data folder" - IDC_OPT_OTHER_DATA_FOLDER_TYPE2 "Specify custom application data folder" - IDC_OPT_OTHER_SHOW_TOOLTIPS "Display tooltips" - IDC_OPT_REC_ALWAYS_RECORD "Always record while playing" - IDC_OPT_REC_BUFFER_SIZE "Size of record buffer size, in events" - IDC_OPT_REC_FOLDER_BROWSE "Browse for destination folder" - IDC_OPT_REC_FOLDER_PATH "Location of destination folder" - IDC_OPT_REC_FOLDER_TYPE "Use default destination folder for recordings" - IDC_OPT_REC_FOLDER_TYPE2 - "Specify custom destination folder for recordings" - IDC_OPT_REC_MIDI_FILE_PPQ - "Time resolution of output MIDI file, in pulses per quarter note" - IDC_OPT_REC_PROMPT_FILENAME - "Prompt for filename before recording; else generate filename" - IDC_PARTS_LIST " " - IDC_PART_AUTO_PLAY "Play part automatically" - IDC_PART_AUTO_VELOCITY "Auto-play note velocity" - IDC_PART_AUTO_WINDOW "Start of auto-play pitch window" -END - -STRINGTABLE PRELOAD DISCARDABLE -BEGIN - IDC_PART_OUT_CONTROLS_THRU "Pass controllers through to output" - IDC_PART_OUT_DEVICE_NAME "MIDI output device name" - IDC_PART_OUT_FIX_HELD_NOTES "Correct held notes that become non-diatonics" - IDC_PART_OUT_LOCAL_CONTROL "Enable local control" - IDC_PART_OUT_PATCH "Patch number, or -1 if none" - IDC_PART_OUT_PORT "MIDI output device index" - IDC_PART_OUT_VOLUME "Output volume, or -1 if none" - IDC_PATCH_AINST_CHANNEL "Output channel number" - IDC_PATCH_AINST_ENABLE "Enable instrument" - IDC_PATCH_AINST_PATCH "Patch number, or -1 if none" - IDC_PATCH_AINST_PORT "MIDI output device index" - IDC_PATCH_AINST_VELOCITY "Note velocity" - IDC_PATCH_AINST_VOLUME "Output volume, or -1 if none" - IDC_PATCH_GEN_KEY "Transposed key signature" - IDC_PATCH_GEN_LEAD_IN "Lead-in length, in measures" - IDC_PATCH_GEN_PPQ "Time resolution, in pulses per quarter note" -END - -STRINGTABLE PRELOAD DISCARDABLE -BEGIN - IDC_PATCH_GEN_TEMPO "Tempo, in beats per minute" - IDC_PATCH_GEN_TEMPO_MULTIPLE "Tempo multiplier" - IDC_PATCH_GEN_TRANSPOSE "Key transposition, in semitones" - IDC_PATCH_METRO_ACCENT_NOTE "Accented metronome note" - IDC_PATCH_METRO_ACCENT_SAME_NOTE "Use same note for accent" - IDC_PATCH_METRO_ACCENT_VEL "Accented note velocity" - IDC_PATCH_METRO_NOTE "Normal metronome note" - IDC_PIANO_CHANNEL "Output channel number" - IDC_PIANO_KEY_COUNT "Number of keys" - IDC_PIANO_PORT "MIDI output device index" - IDC_PIANO_START_NOTE "Keyboard's first note" - IDC_PIANO_VELOCITY "Output velocity" -END - STRINGTABLE PRELOAD DISCARDABLE BEGIN IDC_SECTION_PROPS_LENGTH "Section length" @@ -1727,11 +1704,11 @@ BEGIN IDC_SECTION_PROPS_START "Section start position" IDC_SONG_PROPS_COMMENTS "Enter one or more comment lines here" IDC_SONG_PROPS_KEY_SIG "Song key signature" - IDC_SONG_PROPS_TEMPO "Song tempo, in beats per minute" END STRINGTABLE PRELOAD DISCARDABLE BEGIN + IDC_SONG_PROPS_TEMPO "Song tempo, in beats per minute" IDC_SONG_PROPS_TIME_SIG_DENOM "Denominator of song's time signature" IDC_SONG_PROPS_TIME_SIG_NUMER "Numerator of song's time signature" IDC_SONG_PROPS_TRANSPOSE "Song transposition amount, in semitones" diff --git a/ChordEase.vcproj b/ChordEase.vcproj index bb6793b..01ea780 100644 --- a/ChordEase.vcproj +++ b/ChordEase.vcproj @@ -1784,14 +1784,6 @@ RelativePath=".\MidiTargetDlg.h" > - - - - @@ -2332,6 +2324,10 @@ RelativePath=".\PartsBar.h" > + + @@ -2356,14 +2352,6 @@ RelativePath=".\Patch.h" > - - - - @@ -2564,30 +2552,6 @@ RelativePath="Round.h" > - - - - - - - - - - - - @@ -3401,6 +3365,10 @@ RelativePath="res\ChordEaseDoc.ico" > + + @@ -3413,6 +3381,18 @@ RelativePath=".\res\header_sort.bmp" > + + + + + + diff --git a/ChordEaseView.cpp b/ChordEaseView.cpp index e0c9e7b..3ca6047 100644 --- a/ChordEaseView.cpp +++ b/ChordEaseView.cpp @@ -14,6 +14,7 @@ 04 07may14 add editing 05 15may14 in SaveUndoState, remove song state's section map 06 02jun14 fix access violation on left button up if empty song + 07 10jun14 add SetChord ChordEase view @@ -723,8 +724,7 @@ bool CChordEaseView::OnDestroyPopupEdit() } if (chord == gEngine.GetChord(iSongChord)) // if chord unchanged return(FALSE); - NotifyUndoableEdit(iSongChord, CHART_UCODE_CHORD_EDIT); - if (!gEngine.SetChord(iSongChord, chord)) + if (!SetChord(m_EditChordIdx, chord)) return(FALSE); UpdateViews(CChordEaseDoc::HINT_CHART); return(TRUE); @@ -919,6 +919,27 @@ bool CChordEaseView::MakeChordPopups(CMenu& Menu, int ChordIdx) return(TRUE); } +bool CChordEaseView::SetChord(int ChordIdx, const CSong::CChord& Chord) +{ + int iSongChord = GetSongChordIndex(ChordIdx); + if (m_ChordSymbol[ChordIdx].m_Name == MEASURE_REPEAT // if repeated measure + || GetSelection().LengthInclusive() > 1 // or multi-chord selection + || gEngine.GetSong().IsMergeable(iSongChord)) { // or merging with adjacent chord + CSongState state; + gEngine.GetSongState(state); + NotifyUndoableEdit(iSongChord, CHART_UCODE_MULTI_CHORD_EDIT); + state.SetChord(GetBeatSelection(), Chord); + if (!gEngine.SetSongState(state)) + return(FALSE); + } else { // single chord edit + NotifyUndoableEdit(iSongChord, CHART_UCODE_CHORD_EDIT); + if (!gEngine.SetChord(iSongChord, Chord)) + return(FALSE); + } + UpdateViews(CChordEaseDoc::HINT_CHART); + return(TRUE); +} + void CChordEaseView::SaveUndoState(CUndoState& State) { // _tprintf(_T("SaveUndoState %d %d\n"), State.GetCtrlID(), State.GetCode()); @@ -951,6 +972,7 @@ void CChordEaseView::SaveUndoState(CUndoState& State) case CHART_UCODE_SECTION_CREATE: case CHART_UCODE_SECTION_DELETE: case CHART_UCODE_SECTION_PROPS: + case CHART_UCODE_MULTI_CHORD_EDIT: { CRefPtr uip; uip.CreateObj(); @@ -1006,6 +1028,7 @@ void CChordEaseView::RestoreUndoState(const CUndoState& State) case CHART_UCODE_SECTION_CREATE: case CHART_UCODE_SECTION_DELETE: case CHART_UCODE_SECTION_PROPS: + case CHART_UCODE_MULTI_CHORD_EDIT: { const CClipboardEditUndoInfo *uip = static_cast(State.GetObj()); @@ -1523,11 +1546,9 @@ void CChordEaseView::OnChordRoot(UINT nID) int iSongChord = GetSongChordIndex(m_EditChordIdx); CSong::CChord ch = gEngine.GetChord(iSongChord); if (note != ch.m_Root) { // if selection changed - NotifyUndoableEdit(iSongChord, CHART_UCODE_CHORD_EDIT); ch.m_Root = note; ch.m_Bass = note; // reset bass note to root - gEngine.SetChord(iSongChord, ch); - UpdateViews(CChordEaseDoc::HINT_CHART); + SetChord(m_EditChordIdx, ch); } } @@ -1538,10 +1559,8 @@ void CChordEaseView::OnChordType(UINT nID) int iSongChord = GetSongChordIndex(m_EditChordIdx); CSong::CChord ch = gEngine.GetChord(iSongChord); if (iType != ch.m_Type) { // if selection changed - NotifyUndoableEdit(iSongChord, CHART_UCODE_CHORD_EDIT); ch.m_Type = iType; - gEngine.SetChord(iSongChord, ch); - UpdateViews(CChordEaseDoc::HINT_CHART); + SetChord(m_EditChordIdx, ch); } } @@ -1552,10 +1571,8 @@ void CChordEaseView::OnChordBass(UINT nID) int iSongChord = GetSongChordIndex(m_EditChordIdx); CSong::CChord ch = gEngine.GetChord(iSongChord); if (note != ch.m_Bass) { // if selection changed - NotifyUndoableEdit(iSongChord, CHART_UCODE_CHORD_EDIT); ch.m_Bass = note; - gEngine.SetChord(iSongChord, ch); - UpdateViews(CChordEaseDoc::HINT_CHART); + SetChord(m_EditChordIdx, ch); } } diff --git a/ChordEaseView.h b/ChordEaseView.h index d11f8cf..bd4f9ac 100644 --- a/ChordEaseView.h +++ b/ChordEaseView.h @@ -10,6 +10,7 @@ 00 12sep13 initial version 01 17apr14 add support for song sections 02 07may14 add editing + 03 10jun14 add SetChord ChordEase view @@ -67,6 +68,7 @@ class CChordEaseView : public CScrollView, public CUndoable bool CanPaste() const; CRect GetChordItemRect(int ChordIdx) const; int GetCurSection() const; + bool SetChord(int ChordIdx, const CSong::CChord& Chord); // Operations public: diff --git a/DragVirtualListCtrl.cpp b/DragVirtualListCtrl.cpp index 852e67e..6407446 100644 --- a/DragVirtualListCtrl.cpp +++ b/DragVirtualListCtrl.cpp @@ -18,6 +18,7 @@ 08 04oct13 add drop position tracking 09 21nov13 derive from extended selection list 10 22nov13 in PreTranslateMessage, do base class if not dragging + 11 12jun14 add drag enable virtual list control with drag reordering @@ -43,6 +44,7 @@ IMPLEMENT_DYNAMIC(CDragVirtualListCtrl, CListCtrlExSel); CDragVirtualListCtrl::CDragVirtualListCtrl() { + m_DragEnable = TRUE; m_Dragging = FALSE; m_TrackDropPos = FALSE; m_ScrollDelta = 0; @@ -113,13 +115,15 @@ END_MESSAGE_MAP() BOOL CDragVirtualListCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) { - NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; - m_Dragging = TRUE; - SetCapture(); - UpdateCursor(pNMListView->ptAction); - m_DropPos = -1; - if (m_TrackDropPos) - SetFocus(); + if (m_DragEnable) { // if drag enabled + NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; + m_Dragging = TRUE; + SetCapture(); + UpdateCursor(pNMListView->ptAction); + m_DropPos = -1; + if (m_TrackDropPos) + SetFocus(); + } *pResult = 0; return(FALSE); // let parent handle notification too } diff --git a/DragVirtualListCtrl.h b/DragVirtualListCtrl.h index 10e31ec..1c60429 100644 --- a/DragVirtualListCtrl.h +++ b/DragVirtualListCtrl.h @@ -14,6 +14,7 @@ 04 06jan10 W64: make OnTimer 64-bit compatible 05 04oct13 add drop position tracking 06 21nov13 derive from extended selection list + 07 12jun14 add drag enable virtual list control with drag reordering @@ -44,6 +45,8 @@ class CDragVirtualListCtrl : public CListCtrlExSel // Attributes public: + void SetDragEnable(bool Enable); + bool GetDragEnable() const; int GetDropPos() const; bool IsDragging() const; void TrackDropPos(bool Enable); @@ -80,6 +83,7 @@ class CDragVirtualListCtrl : public CListCtrlExSel }; // Member data + bool m_DragEnable; // true if drag is enabled bool m_Dragging; // true if items are being dragged bool m_TrackDropPos; // true if tracking drop position int m_ScrollDelta; // scroll by this amount per timer tick @@ -93,6 +97,16 @@ class CDragVirtualListCtrl : public CListCtrlExSel void AutoScroll(const CPoint& Cursor); }; +inline void CDragVirtualListCtrl::SetDragEnable(bool Enable) +{ + m_DragEnable = Enable; +} + +inline bool CDragVirtualListCtrl::GetDragEnable() const +{ + return(m_DragEnable); +} + inline int CDragVirtualListCtrl::GetDropPos() const { return(m_DropPos); diff --git a/DurationComboBox.cpp b/DurationComboBox.cpp index b4a83c3..1960064 100644 --- a/DurationComboBox.cpp +++ b/DurationComboBox.cpp @@ -8,6 +8,7 @@ revision history: rev date comments 00 17oct13 initial version + 01 10jun14 let parent handle notifications too note duration combo box @@ -156,8 +157,8 @@ void CDurationComboBox::UpdateValFromString(CString Str) BEGIN_MESSAGE_MAP(CDurationComboBox, CComboBox) //{{AFX_MSG_MAP(CDurationComboBox) - ON_CONTROL_REFLECT(CBN_KILLFOCUS, OnKillfocus) - ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelchange) + ON_CONTROL_REFLECT_EX(CBN_KILLFOCUS, OnKillfocus) + ON_CONTROL_REFLECT_EX(CBN_SELCHANGE, OnSelchange) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -185,14 +186,15 @@ void CDurationComboBox::PreSubclassWindow() } } -void CDurationComboBox::OnKillfocus() +BOOL CDurationComboBox::OnKillfocus() { CString s; GetWindowText(s); UpdateValFromString(s); + return(FALSE); // let parent handle notification too } -void CDurationComboBox::OnSelchange() +BOOL CDurationComboBox::OnSelchange() { int iItem = GetCurSel(); if (iItem >= 0) { @@ -200,6 +202,7 @@ void CDurationComboBox::OnSelchange() GetLBText(iItem, s); UpdateValFromString(s); } + return(FALSE); // let parent handle notification too } BOOL CDurationComboBox::PreTranslateMessage(MSG* pMsg) diff --git a/DurationComboBox.h b/DurationComboBox.h index 7b8266c..09be907 100644 --- a/DurationComboBox.h +++ b/DurationComboBox.h @@ -8,6 +8,7 @@ revision history: rev date comments 00 17oct13 initial version + 01 10jun14 let parent handle notifications too note duration combo box @@ -68,8 +69,8 @@ class CDurationComboBox : public CComboBox // Generated message map functions protected: //{{AFX_MSG(CDurationComboBox) - afx_msg void OnKillfocus(); - afx_msg void OnSelchange(); + afx_msg BOOL OnKillfocus(); + afx_msg BOOL OnSelchange(); //}}AFX_MSG DECLARE_MESSAGE_MAP() diff --git a/Engine.cpp b/Engine.cpp index 3671b4b..a5ab4a4 100644 --- a/Engine.cpp +++ b/Engine.cpp @@ -1,4 +1,4 @@ -]// Copyleft 2013 Chris Korda +// Copyleft 2013 Chris Korda // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 of the License, or any later version. @@ -544,6 +544,17 @@ inline int CEngine::NormParamToEnum(double Val, int Enums) return(CLAMP(ival, 0, Enums - 1)); } +inline int CEngine::NormParamToInt(double Val, int Min, int Max) +{ + int ival = round(Val); + return(CLAMP(ival, Min, Max)); +} + +inline int CEngine::NormParamToMidiVal(double Val) +{ + return(NormParamToInt(Val * MIDI_NOTE_MAX, 0, MIDI_NOTE_MAX)); +} + inline bool CEngine::UpdateTrigger(bool Input, bool& State) { if (Input == State) @@ -563,6 +574,7 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V for (int iTarg = 0; iTarg < CPart::MIDI_TARGETS; iTarg++) { // for each target const CMidiTarget& targ = part.m_MidiTarget[iTarg]; if (targ.IsMatch(Inst, Event, Ctrl)) { // if target matches input parameters + part.m_MidiShadow[iTarg] = static_cast(Val); double pos = targ.GetNormPos(Val); bool TargetChanged = FALSE; switch (iTarg) { @@ -573,16 +585,16 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V UMT(part.m_Function, NormParamToEnum(pos, CPart::FUNCTIONS)); break; case CPart::MIDI_TARGET_IN_ZONE_LOW: - UMT(part.m_In.ZoneLow, round(pos * MIDI_NOTE_MAX)); + UMT(part.m_In.ZoneLow, NormParamToMidiVal(pos)); break; case CPart::MIDI_TARGET_IN_ZONE_HIGH: - UMT(part.m_In.ZoneHigh, round(pos * MIDI_NOTE_MAX)); + UMT(part.m_In.ZoneHigh, NormParamToMidiVal(pos)); break; case CPart::MIDI_TARGET_IN_TRANSPOSE: - UMT(part.m_In.Transpose, round((pos * 2 - 1) * OCTAVE)); + UMT(part.m_In.Transpose, NormParamToInt((pos * 2 - 1) * OCTAVE, -MIDI_NOTE_MAX, MIDI_NOTE_MAX)); break; case CPart::MIDI_TARGET_IN_VEL_OFFSET: - UMT(part.m_In.VelOffset, round((pos * 2 - 1) * MIDI_NOTE_MAX)); + UMT(part.m_In.VelOffset, NormParamToInt((pos * 2 - 1) * MIDI_NOTE_MAX, -MIDI_NOTE_MAX, MIDI_NOTE_MAX)); break; case CPart::MIDI_TARGET_IN_NON_DIATONIC: UMT(part.m_In.NonDiatonic, NormParamToEnum(pos, CPart::INPUT::NON_DIATONIC_RULES)); @@ -590,7 +602,7 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V case CPart::MIDI_TARGET_IN_CC_NOTE: { // convert continuous controller position to input note - CNote note(round(pos * MIDI_NOTE_MAX)); + CNote note(NormParamToMidiVal(pos)); // if non-diatonic rule is disable, apply rule to input note int iRule = part.m_In.NonDiatonic; if (iRule == CPart::INPUT::NDR_DISABLE @@ -615,19 +627,22 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V } break; case CPart::MIDI_TARGET_IN_CC_NOTE_VEL: - m_PartState[iPart].m_InputCCNoteVel = round(pos * MIDI_NOTE_MAX); + m_PartState[iPart].m_InputCCNoteVel = NormParamToMidiVal(pos); break; case CPart::MIDI_TARGET_OUT_PATCH: - UMT(part.m_Out.Patch, round(pos * MIDI_NOTE_MAX)); + UMT(part.m_Out.Patch, NormParamToMidiVal(pos)); OutputPatch(part.m_Out.Inst, part.m_Out.Patch); break; case CPart::MIDI_TARGET_OUT_VOLUME: - UMT(part.m_Out.Volume, round(pos * MIDI_NOTE_MAX)); + UMT(part.m_Out.Volume, NormParamToMidiVal(pos)); OutputControl(part.m_Out.Inst, VOLUME, part.m_Out.Volume); break; case CPart::MIDI_TARGET_OUT_ANTICIPATION: UMT(part.m_Out.Anticipation, pos); break; + case CPart::MIDI_TARGET_OUT_FIX_HELD_NOTES: + UMT(part.m_Out.FixHeldNotes, pos > 0); + break; case CPart::MIDI_TARGET_LEAD_HARM_INTERVAL: UMT(part.m_Lead.Harm.Interval, round(pos * CDiatonic::DEGREES)); break; @@ -671,7 +686,7 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V m_PartState[iPart].OnTimeChange(part, m_Patch.m_PPQ); break; case CPart::MIDI_TARGET_BASS_APPROACH_TRIGGER: - if (pos > 0) { + if (pos > 0 && m_Song.GetChordCount()) { // if positive transition and song not empty if (!m_PartState[iPart].m_BassApproachTrigger) { // if not already triggered m_PartState[iPart].m_BassApproachTrigger = TRUE; // set triggered state SetBassApproachTarget(iPart); // compute approach target time and chord @@ -687,16 +702,15 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V UMT(part.m_Auto.Play, pos > 0); break; case CPart::MIDI_TARGET_AUTO_WINDOW: - UMT(part.m_Auto.Window, round(pos * MIDI_NOTE_MAX)); + UMT(part.m_Auto.Window, NormParamToMidiVal(pos)); break; case CPart::MIDI_TARGET_AUTO_VELOCITY: - UMT(part.m_Auto.Velocity, round(pos * MIDI_NOTE_MAX)); + UMT(part.m_Auto.Velocity, NormParamToMidiVal(pos)); break; default: NODEFAULTCASE; // missing target handler } - if (TargetChanged) - OnMidiTargetChange(iPart, iTarg); + OnMidiTargetChange(iPart, MAKELONG(iTarg, TargetChanged)); } } } @@ -704,6 +718,7 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V for (int iTarg = 0; iTarg < CPatch::MIDI_TARGETS; iTarg++) { // for each target const CMidiTarget& targ = m_Patch.m_MidiTarget[iTarg]; if (targ.IsMatch(Inst, Event, Ctrl)) { // if target matches input parameters + m_Patch.m_MidiShadow[iTarg] = static_cast(Val); double pos = targ.GetNormPos(Val); bool TargetChanged = FALSE; switch (iTarg) { @@ -729,7 +744,7 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V UMT(m_Patch.m_Metronome.Enable, pos > 0); break; case CPatch::MIDI_TARGET_METRO_VOLUME: - UMT(m_Patch.m_Metronome.Volume, round(pos * MIDI_NOTE_MAX)); + UMT(m_Patch.m_Metronome.Volume, NormParamToMidiVal(pos)); OutputControl(m_Patch.m_Metronome.Inst, VOLUME, m_Patch.m_Metronome.Volume); break; case CPatch::MIDI_TARGET_PLAY: @@ -763,8 +778,8 @@ inline void CEngine::UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int V default: NODEFAULTCASE; // missing target handler } - if (TargetChanged) - OnMidiTargetChange(-1, iTarg); // negative part index indicates patch + // negative part index indicates patch + OnMidiTargetChange(-1, MAKELONG(iTarg, TargetChanged)); } } } diff --git a/Engine.h b/Engine.h index 14ae746..174b552 100644 --- a/Engine.h +++ b/Engine.h @@ -298,6 +298,8 @@ class CEngine : public CEngineMidi { return(TRUE); } static int NormParamToEnum(double Val, int Enums); + static int NormParamToInt(double Val, int Min, int Max); + static int NormParamToMidiVal(double Val); static bool UpdateTrigger(bool Input, bool& State); void UpdateMidiTarget(CMidiInst Inst, int Event, int Ctrl, int Val); int GetChordIndex(int Tick) const; diff --git a/Globals.h b/Globals.h index 6f1b19b..96e09ca 100644 --- a/Globals.h +++ b/Globals.h @@ -191,8 +191,7 @@ enum { // user windows messages UWM_ENGINEERROR, // wParam: string resource ID, lParam: CEngine* UWM_ENGINENOTIFY, // wParam: notification code, lParam: CEngine* UWM_DEVICENODECHANGE, // wParam: none, lParam: none - UWM_MIDIROWEDIT, // wParam: row index, lParam: control ID - UWM_MIDITARGETCHANGE, // wParam: part index, lParam: target index + UWM_MIDITARGETCHANGE, // wParam: part index, lParam: LSW target index, HSW change flag UWM_MIDIINPUTDATA, // wParam: MIDI message and device index in MSB, lParam: timestamp UWM_MIDIOUTPUTDATA, // wParam: MIDI message and device index in MSB, lParam: timestamp UWM_COLORSTATUSBARPANE, // wParam: HDC, lParam: pane index, return COLORREF diff --git a/GridCtrl.cpp b/GridCtrl.cpp index 4fc5edf..b516919 100644 --- a/GridCtrl.cpp +++ b/GridCtrl.cpp @@ -118,9 +118,9 @@ CWnd *CGridCtrl::CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, const RECT& rect, C return(pEdit); } -void CGridCtrl::OnItemChange(int Row, int Col, LPCTSTR Text) +void CGridCtrl::OnItemChange(LPCTSTR Text) { - SetItemText(Row, Col, Text); + SetItemText(m_EditRow, m_EditCol, Text); } BEGIN_MESSAGE_MAP(CGridCtrl, CDragVirtualListCtrl) @@ -228,6 +228,6 @@ void CGridCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) LRESULT CGridCtrl::OnTextChange(WPARAM wParam, LPARAM lParam) { - OnItemChange(m_EditRow, m_EditCol, LPCTSTR(wParam)); + OnItemChange(LPCTSTR(wParam)); return(0); } diff --git a/GridCtrl.h b/GridCtrl.h index 00ed56d..a3a4909 100644 --- a/GridCtrl.h +++ b/GridCtrl.h @@ -80,7 +80,7 @@ class CGridCtrl : public CDragVirtualListCtrl // Overrideables virtual CWnd *CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); - virtual void OnItemChange(int Row, int Col, LPCTSTR Text); + virtual void OnItemChange(LPCTSTR Text); // Helpers void GotoSubitem(int DeltaRow, int DeltaCol); diff --git a/HelpIDs.h b/HelpIDs.h index 0e532db..d9ae5a4 100644 --- a/HelpIDs.h +++ b/HelpIDs.h @@ -8,24 +8,70 @@ #define IDH_File_menu_Open 8 #define IDH_File_menu_Save 9 #define IDH_File_menu_Save_As 10 -#define IDH_File_menu_Exit 11 -#define IDH_Edit_menu_Undo_Redo 12 -#define IDH_Edit_menu_Clipboard 13 -#define IDH_Edit_menu_Cut 14 -#define IDH_Edit_menu_Copy 15 -#define IDH_Edit_menu_Paste 16 -#define IDH_Edit_menu_Insert 17 -#define IDH_Edit_menu_Delete 18 -#define IDH_Transport_menu_Play_Stop 19 -#define IDH_Transport_menu_Pause 20 -#define IDH_Transport_menu_Rewind 21 -#define IDH_Transport_menu_Repeat 22 -#define IDH_Transport_menu_Record 23 -#define IDH_Transport_menu_Next_Section 24 -#define IDH_View_menu_Toolbar 25 -#define IDH_View_menu_Status_bar 26 -#define IDH_Help_menu_Help_topics 27 -#define IDH_Help_menu_ChordEase_on_the_Web 28 -#define IDH_Help_menu_Check_for_updates 29 -#define IDH_Help_menu_About 30 -#define IDH_Loose_ends_Shortcuts 31 +#define IDH_File_menu_Edit_Text 11 +#define IDH_File_menu_Properties 12 +#define IDH_File_menu_Print_Setup 13 +#define IDH_File_menu_Print_Preview 14 +#define IDH_File_menu_Print 15 +#define IDH_File_menu_Exit 16 +#define IDH_Edit_menu_Undo_Redo 17 +#define IDH_Edit_menu_Clipboard 18 +#define IDH_Edit_menu_Cut 19 +#define IDH_Edit_menu_Copy 20 +#define IDH_Edit_menu_Paste 21 +#define IDH_Edit_menu_Insert 22 +#define IDH_Edit_menu_Delete 23 +#define IDH_Edit_menu_Select_All 24 +#define IDH_Edit_menu_Rename 25 +#define IDH_Edit_menu_Create_Section 26 +#define IDH_Edit_menu_Delete_Section 27 +#define IDH_Edit_menu_Section_Properties 28 +#define IDH_Edit_menu_List_Sections 29 +#define IDH_Edit_menu_Options 30 +#define IDH_Patch_menu_New_Patch 31 +#define IDH_Patch_menu_Open_Patch 32 +#define IDH_Patch_menu_Save_Patch 33 +#define IDH_Patch_menu_Save_Patch_As 34 +#define IDH_Transport_menu_Play_Stop 35 +#define IDH_Transport_menu_Pause 36 +#define IDH_Transport_menu_Rewind 37 +#define IDH_Transport_menu_Repeat 38 +#define IDH_Transport_menu_Record 39 +#define IDH_Transport_menu_Next_Section 40 +#define IDH_Transport_menu_Next_Chord 41 +#define IDH_Transport_menu_Previous_Chord 42 +#define IDH_Transport_menu_Auto_Rewind 43 +#define IDH_MIDI_menu_Devices 44 +#define IDH_MIDI_menu_Input 45 +#define IDH_MIDI_menu_Output 46 +#define IDH_MIDI_menu_Learn 47 +#define IDH_MIDI_menu_Assignments 48 +#define IDH_MIDI_menu_Note_Mappings 49 +#define IDH_MIDI_menu_Chase_Events 50 +#define IDH_MIDI_menu_Reset_All_Targets 51 +#define IDH_MIDI_menu_Panic 52 +#define IDH_View_menu_Toolbar 53 +#define IDH_View_menu_Status_bar 54 +#define IDH_View_menu_Patch_bar 55 +#define IDH_View_menu_Parts_bar 56 +#define IDH_View_menu_Piano 57 +#define IDH_View_menu_Output_Notes 58 +#define IDH_View_menu_Threads 59 +#define IDH_View_menu_Record_Player 60 +#define IDH_Help_menu_Help_topics 61 +#define IDH_Help_menu_ChordEase_on_the_Web 62 +#define IDH_Help_menu_Check_for_updates 63 +#define IDH_Help_menu_Demo 64 +#define IDH_Help_menu_About 65 +#define IDH_Options_Chart_Measures_per_line 66 +#define IDH_Options_Chart_Font 67 +#define IDH_Options_Chart_Default_font 68 +#define IDH_Options_Record_Always_record 69 +#define IDH_Options_Record_Prompt_for_filename 70 +#define IDH_Options_Record_Buffer_size 71 +#define IDH_Options_Record_MIDI_file_resolution 72 +#define IDH_Options_Record_Output_folder 73 +#define IDH_Options_Other_Automatically_check_for_updates 74 +#define IDH_Options_Other_Show_tooltips 75 +#define IDH_Options_Other_Application_data_folder 76 +#define IDH_Loose_ends_Shortcuts 77 diff --git a/HelpResMap.h b/HelpResMap.h index c0b4212..d121a46 100644 --- a/HelpResMap.h +++ b/HelpResMap.h @@ -13,22 +13,65 @@ */ -{ID_APP_ABOUT, IDH_Help_menu_About}, -//{ID_APP_CHECK_FOR_UPDATES, IDH_Options_View_Automatically_check_for_updates}, -{ID_APP_EXIT, IDH_File_menu_Exit}, -{ID_APP_HOME_PAGE, IDH_Help_menu_ChordEase_on_the_Web}, -{ID_EDIT_COPY, IDH_Edit_menu_Copy}, -{ID_EDIT_CUT, IDH_Edit_menu_Cut}, -{ID_EDIT_DELETE, IDH_Edit_menu_Delete}, -{ID_EDIT_INSERT, IDH_Edit_menu_Insert}, -//{ID_EDIT_OPTIONS, IDH_Options_View_Zoom_step_size}, -{ID_EDIT_PASTE, IDH_Edit_menu_Paste}, -{ID_EDIT_REDO, IDH_Edit_menu_Undo_Redo}, -//{ID_EDIT_SELECT_ALL, IDH_Navigation_Selecting_audio}, -{ID_EDIT_UNDO, IDH_Edit_menu_Undo_Redo}, -{ID_FILE_NEW, IDH_File_menu_New}, -{ID_FILE_OPEN, IDH_File_menu_Open}, -{ID_FILE_SAVE, IDH_File_menu_Save}, -{ID_FILE_SAVE_AS, IDH_File_menu_Save_As}, -{ID_HELP_FINDER, IDH_Help_menu_Help_topics}, - +{ID_APP_ABOUT, IDH_Help_menu_About}, +{ID_APP_CHECK_FOR_UPDATES, IDH_Help_menu_Check_for_updates}, +{ID_APP_DEMO, IDH_Help_menu_Demo}, +{ID_APP_EXIT, IDH_File_menu_Exit}, +{ID_APP_HOME_PAGE, IDH_Help_menu_ChordEase_on_the_Web}, +{ID_EDIT_COPY, IDH_Edit_menu_Copy}, +{ID_EDIT_CUT, IDH_Edit_menu_Cut}, +{ID_EDIT_DELETE, IDH_Edit_menu_Delete}, +{ID_EDIT_INSERT, IDH_Edit_menu_Insert}, +{ID_EDIT_OPTIONS, IDH_Edit_menu_Options}, +{ID_EDIT_PASTE, IDH_Edit_menu_Paste}, +{ID_EDIT_REDO, IDH_Edit_menu_Undo_Redo}, +{ID_EDIT_RENAME, IDH_Edit_menu_Rename}, +{ID_EDIT_SECTION_CREATE, IDH_Edit_menu_Create_Section}, +{ID_EDIT_SECTION_DELETE, IDH_Edit_menu_Delete_Section}, +{ID_EDIT_SECTION_LIST, IDH_Edit_menu_List_Sections}, +{ID_EDIT_SECTION_PROPS, IDH_Edit_menu_Section_Properties}, +{ID_EDIT_SELECT_ALL, IDH_Edit_menu_Select_All}, +{ID_EDIT_UNDO, IDH_Edit_menu_Undo_Redo}, +{ID_FILE_EDIT, IDH_File_menu_Edit_Text}, +{ID_FILE_NEW, IDH_File_menu_New}, +{ID_FILE_OPEN, IDH_File_menu_Open}, +{ID_FILE_PRINT, IDH_File_menu_Print}, +{ID_FILE_PRINT_PREVIEW, IDH_File_menu_Print_Preview}, +{ID_FILE_PRINT_SETUP, IDH_File_menu_Print_Setup}, +{ID_FILE_PROPERTIES, IDH_File_menu_Properties}, +{ID_FILE_SAVE, IDH_File_menu_Save}, +{ID_FILE_SAVE_AS, IDH_File_menu_Save_As}, +{ID_HELP_FINDER, IDH_Help_menu_Help_topics}, +{ID_MIDI_ASSIGNMENTS, IDH_MIDI_menu_Assignments}, +{ID_MIDI_CHASE_EVENTS, IDH_MIDI_menu_Chase_Events}, +{ID_MIDI_DEVICES, IDH_MIDI_menu_Devices}, +{ID_MIDI_INPUT, IDH_MIDI_menu_Input}, +{ID_MIDI_LEARN, IDH_MIDI_menu_Learn}, +{ID_MIDI_NOTE_MAPPINGS, IDH_MIDI_menu_Note_Mappings}, +{ID_MIDI_OUTPUT, IDH_MIDI_menu_Output}, +{ID_MIDI_PANIC, IDH_MIDI_menu_Panic}, +{ID_MIDI_RESET_ALL, IDH_MIDI_menu_Reset_All_Targets}, +{ID_PATCH_NEW, IDH_Patch_menu_New_Patch}, +{ID_PATCH_OPEN, IDH_Patch_menu_Open_Patch}, +{ID_PATCH_SAVE, IDH_Patch_menu_Save_Patch}, +{ID_PATCH_SAVE_AS, IDH_Patch_menu_Save_Patch_As}, +{ID_TRANSPORT_AUTO_REWIND, IDH_Transport_menu_Auto_Rewind}, +{ID_TRANSPORT_NEXT_CHORD, IDH_Transport_menu_Next_Chord}, +{ID_TRANSPORT_NEXT_SECTION, IDH_Transport_menu_Next_Section}, +{ID_TRANSPORT_PAUSE, IDH_Transport_menu_Pause}, +{ID_TRANSPORT_PLAY, IDH_Transport_menu_Play_Stop}, +{ID_TRANSPORT_PREV_CHORD, IDH_Transport_menu_Previous_Chord}, +{ID_TRANSPORT_RECORD, IDH_Transport_menu_Record}, +{ID_TRANSPORT_REPEAT, IDH_Transport_menu_Repeat}, +{ID_TRANSPORT_REWIND, IDH_Transport_menu_Rewind}, +{ID_VIEW_OUTPUT_NOTES, IDH_View_menu_Output_Notes}, +{ID_VIEW_PARTS, IDH_View_menu_Parts_bar}, +{ID_VIEW_PATCH, IDH_View_menu_Patch_bar}, +{ID_VIEW_PIANO, IDH_View_menu_Piano}, +{ID_VIEW_RECORD_PLAYER, IDH_View_menu_Record_Player}, +{ID_VIEW_STATUS_BAR, IDH_View_menu_Status_bar}, +{ID_VIEW_THREADS, IDH_View_menu_Threads}, +{ID_VIEW_TOOLBAR, IDH_View_menu_Toolbar}, +{IDD_OPT_CHART, IDH_Options_Chart_Measures_per_line}, +{IDD_OPT_OTHER, IDH_Options_Other_Automatically_check_for_updates}, +{IDD_OPT_RECORD, IDH_Options_Record_Always_record}, diff --git a/ListCtrlExSel.cpp b/ListCtrlExSel.cpp index d70f44e..20a8d17 100644 --- a/ListCtrlExSel.cpp +++ b/ListCtrlExSel.cpp @@ -9,6 +9,7 @@ rev date comments 00 21nov13 initial version 01 13feb14 add SetSelected + 02 15jun14 add tool tip support extended selection list control @@ -168,13 +169,72 @@ void CListCtrlExSel::FixContextMenuPoint(CPoint& Point) } } +INT_PTR CListCtrlExSel::OnToolHitTest(CPoint point, TOOLINFO* pTI) const +{ + LVHITTESTINFO hti; + hti.pt = point; + ListView_SubItemHitTest(m_hWnd, &hti); // use macro to avoid const issue + CRect rClient; + GetClientRect(rClient); + pTI->hwnd = m_hWnd; + // return unique ID for each item, causing each item to get its own tool tip; + // clear ID's most significant bit so ID range is valid even if subitem is -1 + pTI->uId = MAKELONG(hti.iItem, hti.iSubItem) & INT_MAX; + pTI->lpszText = LPSTR_TEXTCALLBACK; // request need text notification + pTI->rect = rClient; + return pTI->uId; +} + +void CListCtrlExSel::EnableToolTips(BOOL bEnable) +{ + SendMessage(LVM_SETTOOLTIPS, 0, 0); // disable list's tooltip control + CListCtrl::EnableToolTips(bEnable); +} + +int CListCtrlExSel::GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text) +{ + return(0); +} + ///////////////////////////////////////////////////////////////////////////// // CListCtrlExSel message map BEGIN_MESSAGE_MAP(CListCtrlExSel, CListCtrl) //{{AFX_MSG_MAP(CListCtrlExSel) //}}AFX_MSG_MAP + ON_NOTIFY_EX(TTN_NEEDTEXTW, 0, OnToolTipNeedText) // Unicode handler + ON_NOTIFY_EX(TTN_NEEDTEXTA, 0, OnToolTipNeedText) // ANSI handler END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CListCtrlExSel message handlers + +BOOL CListCtrlExSel::OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult) +{ + CPoint pt(GetMessagePos()); + ScreenToClient(&pt); + LVHITTESTINFO hti; + hti.pt = pt; + ListView_SubItemHitTest(m_hWnd, &hti); + CString sText; + int nID = GetToolTipText(&hti, sText); // get resource ID or string from derived class + if (!nID && sText.IsEmpty()) // if neither resource ID nor string provided + return(FALSE); // no tip + USES_CONVERSION; + if (pNMHDR->code == TTN_NEEDTEXTA) { // if ANSI notification + TOOLTIPTEXTA *pTTT = (TOOLTIPTEXTA *)pNMHDR; + if (nID) { // if resource ID provided, use it + pTTT->lpszText = LPSTR(MAKEINTRESOURCE(nID)); + pTTT->hinst = AfxGetResourceHandle(); + } else // use string + strncpy(pTTT->szText, T2CA(sText), _countof(pTTT->szText)); + } else { // Unicode notification + TOOLTIPTEXTW *pTTT = (TOOLTIPTEXTW *)pNMHDR; + if (nID) { // if resource ID provided, use it + pTTT->lpszText = LPWSTR(MAKEINTRESOURCE(nID)); + pTTT->hinst = AfxGetResourceHandle(); + } else // use string + wcsncpy(pTTT->szText, T2CW(sText), _countof(pTTT->szText)); + } + return(TRUE); +} diff --git a/ListCtrlExSel.h b/ListCtrlExSel.h index de7e957..4cfe0bf 100644 --- a/ListCtrlExSel.h +++ b/ListCtrlExSel.h @@ -9,6 +9,7 @@ rev date comments 00 21nov13 initial version 01 13feb14 add SetSelected + 02 15jun14 add tool tip support extended selection list control @@ -32,7 +33,9 @@ class CListCtrlExSel : public CListCtrl { DECLARE_DYNCREATE(CListCtrlExSel) public: +// Construction CListCtrlExSel(); + virtual ~CListCtrlExSel(); // Types struct COL_INFO { // column info @@ -61,20 +64,24 @@ class CListCtrlExSel : public CListCtrl bool SaveColumnWidths(LPCTSTR Section, LPCTSTR Key); bool LoadColumnWidths(LPCTSTR Section, LPCTSTR Key); void FixContextMenuPoint(CPoint& Point); + void EnableToolTips(BOOL bEnable = TRUE); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CListCtrlExSel) + public: + virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const; //}}AFX_VIRTUAL -// Implementation - virtual ~CListCtrlExSel(); - // Generated message map functions protected: //{{AFX_MSG(CListCtrlExSel) //}}AFX_MSG + afx_msg BOOL OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult); DECLARE_MESSAGE_MAP() + +// Overrideables + virtual int GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text); }; ///////////////////////////////////////////////////////////////////////////// diff --git a/MainFrm.cpp b/MainFrm.cpp index 9ec6c2d..55cf5b0 100644 --- a/MainFrm.cpp +++ b/MainFrm.cpp @@ -11,6 +11,7 @@ 01 22apr14 add piano dialog 02 28apr14 in OnEngineNotify, add device state change handler 03 30apr14 add OnDropFiles + 04 04jun14 in CreateEngine, fix opening patch via command line ChordEase main frame @@ -300,17 +301,22 @@ bool CMainFrame::CreateEngine() return(FALSE); CString ChordDictPath(theApp.MakeDataFolderPath(CHORD_DICTIONARY_FILE_NAME, TRUE)); gEngine.ReadChordDictionary(ChordDictPath); // read chord dictionary + bool CmdLinePatchOpen; if (!theApp.m_PatchPath.IsEmpty()) // if patch specified on command line - OpenPatch(theApp.m_PatchPath); - else // patch not specified + CmdLinePatchOpen = OpenPatch(theApp.m_PatchPath); // open command line patch + else { // patch not specified + CmdLinePatchOpen = FALSE; m_PatchDoc.New(); // initialize patch document - CPatch patch; - CString PatchPath(theApp.MakeDataFolderPath(PATCH_INI_FILE_NAME, TRUE)); - if (PathFileExists(PatchPath)) { // if patch file exists - if (!patch.Read(PatchPath)) // read patch file - patch.Reset(); // read failed; avoid partial data } - SetPatch(patch, TRUE); // update ports for current devices + if (!CmdLinePatchOpen) { // if patch wasn't opened via command line + CPatch patch; + CString PatchPath(theApp.MakeDataFolderPath(PATCH_INI_FILE_NAME, TRUE)); + if (PathFileExists(PatchPath)) { // if patch file exists + if (!patch.Read(PatchPath)) // read patch file + patch.Reset(); // read failed; avoid partial data + } + SetPatch(patch, TRUE); // update ports for current devices + } return(TRUE); } @@ -456,6 +462,24 @@ void CMainFrame::UpdateHookMidiOutput() || m_OutputNotesBar.IsWindowVisible() != 0); } +int CMainFrame::GetCtrlMidiTarget(CWnd *pWnd, int& PartIdx) const +{ + CWnd *pParent = pWnd->GetParent(); + ASSERT(pParent != NULL); + if (pParent->IsKindOf(RUNTIME_CLASS(CComboBox))) // if parent is combo box + pWnd = pParent; + UINT nID = pWnd->GetDlgCtrlID(); + int iTarget; + if (m_PatchBar.IsChild(pWnd)) { + iTarget = CPatchMidiTargetDlg::FindTargetByCtrlID(nID); + PartIdx = -1; + } else { + iTarget = CPartMidiTargetDlg::FindTargetByCtrlID(nID); + PartIdx = m_PartsBar.GetCurPart(); + } + return(iTarget); +} + void CMainFrame::ApplyOptions(const COptionsInfo& PrevOpts, bool ForceUpdate) { // if chart measures per line or font changed @@ -466,6 +490,15 @@ void CMainFrame::ApplyOptions(const COptionsInfo& PrevOpts, bool ForceUpdate) // if always record option changed if (m_Options.m_Record.AlwaysRecord != PrevOpts.m_Record.AlwaysRecord) gEngine.Record(m_Options.m_Record.AlwaysRecord != 0); // update record state + if (m_Options.m_Other.ShowTooltips != PrevOpts.m_Other.ShowTooltips || ForceUpdate) + EnableAppToolTips(m_Options.m_Other.ShowTooltips != 0); +} + +void CMainFrame::EnableAppToolTips(bool Enable) +{ + m_PatchBar.GetMidiTargetDlg().EnableToolTips(Enable); + m_PartsBar.GetMidiTargetDlg().EnableToolTips(Enable); + m_PartsBar.GetListCtrl().EnableToolTips(Enable); } bool CMainFrame::CheckForUpdates(bool Explicit) @@ -733,6 +766,8 @@ CString CMainFrame::GetUndoTitle(const CUndoState& State) switch (State.GetCode()) { case UCODE_BASE_PATCH: s = m_PatchBar.GetControlCaption(State.GetCtrlID()); + if (s.IsEmpty()) + s.LoadString(State.GetCtrlID()); // assume ID is list column string break; case UCODE_PART: s = m_PartsBar.GetPageView()->GetControlCaption(State.GetCtrlID()); @@ -1137,39 +1172,50 @@ LRESULT CMainFrame::OnMidiTargetChange(WPARAM wParam, LPARAM lParam) #include "PartMidiTargetDef.h" // map part MIDI targets to part pages }; static const int PatchMidiTargetPage[CPatch::MIDI_TARGETS] = { - #define PATCHMIDITARGETDEF(name, page) CPatchBar::PAGE_##page, + #define PATCHMIDITARGETDEF(name, page, tag) CPatchBar::PAGE_##page, #include "PatchMidiTargetDef.h" // map patch MIDI targets to patch pages }; -// _tprintf(_T("CMainFrame::OnMidiTargetChange %d %d\n"), wParam, lParam); int iPart = static_cast(wParam); - int iTarget = static_cast(lParam); + int iTarget = LOWORD(lParam); + int bChanged = HIWORD(lParam); +// _tprintf(_T("CMainFrame::OnMidiTargetChange %d %d (%d)\n"), iPart, iTarget, bChanged); if (iPart >= 0) { // if part target - int iPage = PartMidiTargetPage[iTarget]; - CPart part(gEngine.GetPart(iPart)); - if (iPage >= 0) { // if valid part page - if (m_MidiChaseEvents) { // if chasing MIDI events - NotifyEdit(0, UCODE_MIDI_CHASE, // save part/page indices + if (iPart == m_PartsBar.GetCurPart() // if current part + && m_PartsBar.GetMidiTargetDlg().IsWindowVisible()) + m_PartsBar.GetMidiTargetDlg().UpdateShadowVal(iTarget); + } else { // patch target + if (m_PatchBar.GetMidiTargetDlg().IsWindowVisible()) + m_PatchBar.GetMidiTargetDlg().UpdateShadowVal(iTarget); + } + if (bChanged) { // if target parameter changed + if (iPart >= 0) { // if part target + int iPage = PartMidiTargetPage[iTarget]; + CPart part(gEngine.GetPart(iPart)); + if (iPage >= 0) { // if valid part page + if (m_MidiChaseEvents && !m_MidiLearn) { // if chasing MIDI events + NotifyEdit(0, UCODE_MIDI_CHASE, // save part/page indices + CUndoable::UE_COALESCE | CUndoable::UE_INSIGNIFICANT); + if (iPart != m_PartsBar.GetCurPart()) + m_PartsBar.SetCurPart(iPart); // chase to target's part + m_PartsBar.SetCurPage(iPage); // chase to target's page + } + if (iPart == m_PartsBar.GetCurPart()) // if target part is showing + m_PartsBar.GetPageView()->UpdatePage(iPage, part); // update page + } else // assume parts list + m_PartsBar.GetListView()->SetSubitems(iPart, part); // update parts list + } else { // patch target + int iPage = PatchMidiTargetPage[iTarget]; + CBasePatch patch; + gEngine.GetBasePatch(patch); + if (m_MidiChaseEvents && !m_MidiLearn) { // if chasing MIDI events + NotifyEdit(0, UCODE_MIDI_CHASE, // save part/page indices CUndoable::UE_COALESCE | CUndoable::UE_INSIGNIFICANT); - if (iPart != m_PartsBar.GetCurPart()) - m_PartsBar.SetCurPart(iPart); // chase to target's part - m_PartsBar.SetCurPage(iPage); // chase to target's page + m_PatchBar.SetCurPage(iPage); // chase to target's page } - if (iPart == m_PartsBar.GetCurPart()) // if target part is showing - m_PartsBar.GetPageView()->UpdatePage(iPage, part); // update page - } else // assume parts list - m_PartsBar.GetListView()->SetSubitems(iPart, part); // update parts list - } else { // patch target - int iPage = PatchMidiTargetPage[iTarget]; - CBasePatch patch; - gEngine.GetBasePatch(patch); - if (m_MidiChaseEvents) { // if chasing MIDI events - NotifyEdit(0, UCODE_MIDI_CHASE, // save part/page indices - CUndoable::UE_COALESCE | CUndoable::UE_INSIGNIFICANT); - m_PatchBar.SetCurPage(iPage); // chase to target's page + m_PatchBar.UpdatePage(iPage, patch); // update page + if (iTarget == CPatch::MIDI_TARGET_TRANSPOSE) // if target is transpose + m_View->UpdateChart(); // update chart view } - m_PatchBar.UpdatePage(iPage, patch); // update page - if (iTarget == CPatch::MIDI_TARGET_TRANSPOSE) // if target is transpose - m_View->UpdateChart(); // update chart view } return(0); } @@ -1186,20 +1232,23 @@ LRESULT CMainFrame::OnMidiInputData(WPARAM wParam, LPARAM lParam) if (pFocusWnd != NULL) { int iTarget = -1; int iPart = -1; - CDialog *pMidiPage = m_PatchBar.GetPage(CPatchBar::PAGE_MidiTarget); - if (pMidiPage->IsChild(pFocusWnd)) { // if patch MIDI control has focus - CMidiTargetRowDlg *pRowDlg = DYNAMIC_DOWNCAST(CMidiTargetRowDlg, pFocusWnd->GetParent()); - if (pRowDlg != NULL) // if control's parent is MIDI row dialog - iTarget = pRowDlg->GetRowIndex(); + CMidiTargetDlg& PatchMTDlg = m_PatchBar.GetMidiTargetDlg(); + // if child of patch MIDI target dialog has focus + if (PatchMTDlg.IsChild(pFocusWnd)) { + iTarget = PatchMTDlg.GetCurSel(); } else { - pMidiPage = m_PartsBar.GetPageView()->GetPage(CPartPageView::PAGE_MidiTarget); - if (pMidiPage->IsChild(pFocusWnd)) { // if part MIDI control has focus + CMidiTargetDlg& PartMTDlg = m_PartsBar.GetMidiTargetDlg(); + // if child of part MIDI target dialog has focus + if (PartMTDlg.IsChild(pFocusWnd)) { iPart = m_PartsBar.GetCurPart(); - if (iPart >= 0) { // if part selected; should be true - CMidiTargetRowDlg *pRowDlg = DYNAMIC_DOWNCAST(CMidiTargetRowDlg, pFocusWnd->GetParent()); - if (pRowDlg != NULL) // if control's parent is MIDI row dialog - iTarget = pRowDlg->GetRowIndex(); - } + if (iPart >= 0) // if part selected; should be true + iTarget = PartMTDlg.GetCurSel(); + } else { // try ordinary patch/part pages + iTarget = GetCtrlMidiTarget(pFocusWnd, iPart); + if (iPart < 0) // if patch target + PatchMTDlg.SetCurSel(iTarget); + else // part target + PartMTDlg.SetCurSel(iTarget); } } if (iTarget >= 0) { // if valid MIDI target @@ -1236,6 +1285,18 @@ LRESULT CMainFrame::OnMidiInputData(WPARAM wParam, LPARAM lParam) SetBasePatch(patch); } } + } else { // MIDI target not found + UINT nID = pFocusWnd->GetDlgCtrlID(); + if (nID == IDC_PART_IN_PORT || nID == IDC_PART_IN_CHAN) { + iPart = m_PartsBar.GetCurPart(); + CPart part(gEngine.GetPart(iPart)); + CMidiInst inst(CMidiEventDlg::GetDevice(wParam), MIDI_CHAN(wParam)); + if (inst != part.m_In.Inst) { + NotifyEdit(nID, UCODE_PART); + part.m_In.Inst = inst; + SetPart(iPart, part); + } + } } } } @@ -1620,8 +1681,23 @@ void CMainFrame::OnMidiLearn() { m_MidiLearn ^= 1; UpdateHookMidiInput(); - m_PatchBar.GetPage(CPatchBar::PAGE_MidiTarget)->SendMessage(WM_COMMAND, ID_MIDI_LEARN); - m_PartsBar.GetPageView()->GetPage(CPartPageView::PAGE_MidiTarget)->SendMessage(WM_COMMAND, ID_MIDI_LEARN); + m_PatchBar.GetMidiTargetDlg().OnLearnChange(); + m_PartsBar.GetMidiTargetDlg().OnLearnChange(); + CWnd *pFocusWnd = GetFocus(); + if (pFocusWnd != NULL) { + CPatchPageDlg *pPage = NULL; + if (m_PatchBar.IsChild(pFocusWnd)) { // if patch bar control has focus + int iPage = m_PatchBar.GetCurPage(); + if (iPage >= 0) + pPage = DYNAMIC_DOWNCAST(CPatchPageDlg, m_PatchBar.GetPage(iPage)); + } else if (m_PartsBar.GetPageView()->IsChild(pFocusWnd)) { // if parts bar control has focus + int iPage = m_PartsBar.GetPageView()->GetCurPage(); + if (iPage >= 0) + pPage = DYNAMIC_DOWNCAST(CPatchPageDlg, m_PartsBar.GetPageView()->GetPage(iPage)); + } + if (pPage != NULL) + pPage->UpdateMidiLearn(); + } } void CMainFrame::OnUpdateMidiLearn(CCmdUI* pCmdUI) diff --git a/MainFrm.h b/MainFrm.h index 07101c8..8b0525b 100644 --- a/MainFrm.h +++ b/MainFrm.h @@ -84,6 +84,8 @@ class CMainFrame : public CFrameWnd, public CUndoable CString GetRecordFilePath() const; void SetRecordFilePath(const CString& Path); bool IsMidiLearn() const; + bool IsMidiChase() const; + int GetCtrlMidiTarget(CWnd *pWnd, int& PartIdx) const; // Operations public: @@ -340,6 +342,7 @@ class CMainFrame : public CFrameWnd, public CUndoable void UpdateHookMidiInput(); void UpdateHookMidiOutput(); void DockControlBarNextTo(CControlBar* pBar, CControlBar* pTargetBar); + void EnableAppToolTips(bool Enable); static UINT CheckForUpdatesThreadFunc(LPVOID Param); // Undo state values @@ -457,6 +460,11 @@ inline bool CMainFrame::IsMidiLearn() const return(m_MidiLearn); } +inline bool CMainFrame::IsMidiChase() const +{ + return(m_MidiChaseEvents); +} + ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} diff --git a/MidiEventDlg.h b/MidiEventDlg.h index 78cf4ed..cb515e8 100644 --- a/MidiEventDlg.h +++ b/MidiEventDlg.h @@ -59,6 +59,7 @@ class CMidiEventDlg : public CChildDlg void ResizeFilters(int ItemIdx = -1, int ItemWidth = 0); void UpdateDevices(); void Pause(bool Enable); + void EnableToolTips(BOOL bEnable = TRUE); static WPARAM MakeParam(DWORD Device, W64UINT MidiMsg); static int GetDevice(WPARAM wParam); @@ -169,6 +170,11 @@ inline void CMidiEventDlg::SetShowCtrlrNames(bool Enable) m_ShowCtrlrNames = Enable; } +inline void CMidiEventDlg::EnableToolTips(BOOL bEnable) +{ + m_List.EnableToolTips(bEnable); +} + inline WPARAM CMidiEventDlg::MakeParam(DWORD Device, W64UINT MidiMsg) { ASSERT(Device < UCHAR_MAX); // device index limited to range of byte diff --git a/MidiTargetColDef.h b/MidiTargetColDef.h index 07d79a9..0149945 100644 --- a/MidiTargetColDef.h +++ b/MidiTargetColDef.h @@ -13,13 +13,15 @@ */ -MIDITARGETCOLDEF(NAME) -MIDITARGETCOLDEF(PORT) -MIDITARGETCOLDEF(CHAN) -MIDITARGETCOLDEF(EVENT) -MIDITARGETCOLDEF(CONTROL) -MIDITARGETCOLDEF(RANGE_START) -MIDITARGETCOLDEF(RANGE_END) +// name align width +MIDITARGETCOLDEF(NAME, LVCFMT_LEFT, 100) +MIDITARGETCOLDEF(PORT, LVCFMT_LEFT, 50) +MIDITARGETCOLDEF(CHAN, LVCFMT_LEFT, 50) +MIDITARGETCOLDEF(EVENT, LVCFMT_LEFT, 60) +MIDITARGETCOLDEF(CONTROL, LVCFMT_LEFT, 50) +MIDITARGETCOLDEF(RANGE_START, LVCFMT_LEFT, 50) +MIDITARGETCOLDEF(RANGE_END, LVCFMT_LEFT, 50) +MIDITARGETCOLDEF(VALUE, LVCFMT_LEFT, 50) #undef MIDITARGETCOLDEF diff --git a/MidiTargetDlg.cpp b/MidiTargetDlg.cpp index b0c5229..9d15ff0 100644 --- a/MidiTargetDlg.cpp +++ b/MidiTargetDlg.cpp @@ -9,6 +9,7 @@ rev date comments 00 19nov13 initial version 01 23apr14 define columns via macro + 02 12jun14 refactor to use grid control instead of row view MIDI target dialog @@ -21,6 +22,7 @@ #include "ChordEase.h" #include "MainFrm.h" #include "MidiTargetDlg.h" +#include "PopupCombo.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -31,47 +33,167 @@ static char THIS_FILE[] = __FILE__; ///////////////////////////////////////////////////////////////////////////// // CMidiTargetDlg dialog -IMPLEMENT_DYNCREATE(CMidiRowView, CRowView) IMPLEMENT_DYNAMIC(CMidiTargetDlg, CChildDlg); -const CRowView::COLINFO CMidiTargetDlg::m_ColInfo[COLUMNS] = { - #define MIDITARGETCOLDEF(name) {IDS_MIDI_TARG_ROW_##name, IDC_MIDI_TARG_COL_##name}, +const CGridCtrl::COL_INFO CMidiTargetDlg::m_ColInfo[COLUMNS] = { + #define MIDITARGETCOLDEF(name, align, width) {IDS_MIDI_TARG_COL_##name, align, width}, #include "MidiTargetColDef.h" }; -CMidiTargetDlg::CMidiTargetDlg(int ViewID, CWnd* pParent /*=NULL*/) +const int CMidiTargetDlg::m_ColToolTip[COLUMNS] = { + #define MIDITARGETCOLDEF(name, align, width) IDC_MIDI_TARG_##name, + #include "MidiTargetColDef.h" +}; + +CMidiTargetDlg::CMidiTargetDlg(CWnd* pParent /*=NULL*/) : CChildDlg(IDD, pParent) { //{{AFX_DATA_INIT(CMidiTargetDlg) //}}AFX_DATA_INIT - m_ViewID = ViewID; - m_View = NULL; - m_CurSel = -1; + m_List.m_pParent = this; + m_List.SetDragEnable(FALSE); + m_TargetNameID = NULL; + m_ListItemHeight = 0; } -CRowDlg *CMidiRowView::CreateRow(int Idx) +void CMidiTargetDlg::SetTargets(const int *TargetNameID, int Targets) { - CMidiTargetRowDlg *pDlg = new CMidiTargetRowDlg; - pDlg->Create(IDD_MIDI_TARGET_ROW); - return(pDlg); + m_Target.SetSize(Targets); + m_TargetNameID = TargetNameID; + m_List.SetItemCountEx(Targets); } -void CMidiRowView::UpdateRow(int Idx) +void CMidiTargetDlg::SetCurSel(int RowIdx) { - ASSERT(0); // update not supported, so shouldn't get here + if (RowIdx >= 0) { // if valid row + m_List.Select(RowIdx); + m_List.EnsureVisible(RowIdx, FALSE); + } else + m_List.Deselect(); } -void CMidiTargetDlg::SetCurSel(int RowIdx) +void CMidiTargetDlg::OnLearnChange() +{ + m_List.Invalidate(); +} + +BOOL CMidiTargetDlg::CTargetGridCtrl::PreCreateWindow(CREATESTRUCT& cs) +{ + cs.dwExStyle |= WS_EX_CLIENTEDGE; // border with sunken edge + return CGridCtrl::PreCreateWindow(cs); +} + +CWnd *CMidiTargetDlg::CTargetGridCtrl::CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) +{ + switch (m_EditCol) { + case CMidiTargetDlg::COL_CHAN: + case CMidiTargetDlg::COL_EVENT: + { + int DropHeight = 100; + const CMidiTarget& targ = m_pParent->GetTarget(m_EditRow); + CPopupCombo *pCombo = CPopupCombo::Factory(0, rect, pParentWnd, nID, DropHeight); + if (pCombo != NULL) { + switch (m_EditCol) { + case CMidiTargetDlg::COL_CHAN: + CChordEaseApp::InitNumericCombo(*pCombo, + CIntRange(1, MIDI_CHANNELS), targ.m_Inst.Chan + 1); + break; + case CMidiTargetDlg::COL_EVENT: + { + for (int iType = 0; iType < CMidiTarget::EVENT_TYPES; iType++) + pCombo->AddString(CMidiTarget::GetEventTypeName(iType)); + pCombo->SetCurSel(targ.m_Event); + } + break; + default: + NODEFAULTCASE; + } + pCombo->ShowDropDown(); + } + return pCombo; + } + case COL_VALUE: + return NULL; + } + return CGridCtrl::CreateEditCtrl(Text, dwStyle, rect, pParentWnd, nID); +} + +void CMidiTargetDlg::CTargetGridCtrl::OnItemChange(LPCTSTR Text) { - if (RowIdx == m_CurSel) // if row unchanged - return; // nothing to do - if (theApp.GetMain()->IsMidiLearn()) { // if learning MIDI assignments - if (m_CurSel >= 0) - GetRow(m_CurSel)->UpdateSelection(); - if (RowIdx >= 0) - GetRow(RowIdx)->UpdateSelection(); + CMidiTarget& targ = m_pParent->GetTarget(m_EditRow); + switch (m_EditCol) { + case COL_PORT: + { + int iPort = _ttoi(Text); + targ.m_Inst.Port = max(iPort, 0); + } + break; + case COL_CHAN: + { + int iChan = _ttoi(Text) - 1; + iChan = CLAMP(iChan, 0, MIDI_CHANNELS - 1); + if (iChan == targ.m_Inst.Chan) // if value unchanged + return; // don't update target + targ.m_Inst.Chan = CLAMP(iChan, 0, MIDI_CHANNELS - 1); + } + break; + case COL_EVENT: + { + CPopupCombo *pCombo = STATIC_DOWNCAST(CPopupCombo, m_EditCtrl); + int iType = pCombo->FindString(0, Text); + if (iType >= 0) { // if text found in combo + if (iType == targ.m_Event) // if value unchanged + return; // don't update target + ASSERT(iType < CMidiTarget::EVENT_TYPES); + targ.m_Event = iType; + } + } + break; + case COL_CONTROL: + { + int ctrl = _ttoi(Text); + targ.m_Control = CLAMP(ctrl, 0, MIDI_NOTE_MAX); + } + break; + case COL_RANGE_START: + targ.m_RangeStart = static_cast(_tstof(Text)); + break; + case COL_RANGE_END: + targ.m_RangeEnd = static_cast(_tstof(Text)); + break; + default: + NODEFAULTCASE; } - m_CurSel = RowIdx; + m_pParent->OnTargetChange(m_EditRow, m_EditCol); // update target +} + +int CMidiTargetDlg::CTargetGridCtrl::GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text) +{ + return(m_pParent->GetToolTipText(pHTI, Text)); +} + +void CMidiTargetDlg::OnTargetChange(int RowIdx, int ColIdx) +{ +} + +int CMidiTargetDlg::GetShadowValue(int RowIdx) +{ + return(0); +} + +int CMidiTargetDlg::GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text) +{ + ASSERT(pHTI->iSubItem < COLUMNS); + if (pHTI->iSubItem < 0) + return(IDC_MIDI_TARGET_LIST); + return(m_ColToolTip[pHTI->iSubItem]); +} + +void CMidiTargetDlg::UpdateShadowVal(int RowIdx) +{ + CRect rItem; + m_List.GetSubItemRect(RowIdx, COL_VALUE, LVIR_LABEL, rItem); + m_List.InvalidateRect(rItem); } void CMidiTargetDlg::DoDataExchange(CDataExchange* pDX) @@ -81,10 +203,6 @@ void CMidiTargetDlg::DoDataExchange(CDataExchange* pDX) //}}AFX_DATA_MAP } -void CMidiTargetDlg::GetTargetToolTip(int RowIdx, int id, NMHDR* pNMHDR) -{ -} - ///////////////////////////////////////////////////////////////////////////// // CMidiTargetDlg message map @@ -92,7 +210,13 @@ BEGIN_MESSAGE_MAP(CMidiTargetDlg, CChildDlg) //{{AFX_MSG_MAP(CMidiTargetDlg) ON_WM_SIZE() ON_WM_CREATE() + ON_NOTIFY(LVN_GETDISPINFO, IDC_MIDI_TARGET_LIST, OnGetdispinfo) + ON_WM_MEASUREITEM() + ON_NOTIFY(NM_CUSTOMDRAW, IDC_MIDI_TARGET_LIST, OnCustomDraw) + ON_WM_CONTEXTMENU() ON_COMMAND(ID_MIDI_LEARN, OnMidiLearn) + ON_UPDATE_COMMAND_UI(ID_MIDI_LEARN, OnUpdateMidiLearn) + ON_COMMAND(ID_MIDI_TARGET_RESET, OnMidiTargetReset) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -103,22 +227,30 @@ int CMidiTargetDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CChildDlg::OnCreate(lpCreateStruct) == -1) return -1; - CRuntimeClass *pFactory = RUNTIME_CLASS(CMidiRowView); - m_View = DYNAMIC_DOWNCAST(CMidiRowView, pFactory->CreateObject()); - DWORD dwStyle = AFX_WS_DEFAULT_VIEW | WS_TABSTOP; - DWORD dwExStyle = WS_EX_CONTROLPARENT; // append view to parent's tab order - CRect r(0, 0, 0, 0); - if (!m_View->CreateEx(dwExStyle, NULL, NULL, dwStyle, r, this, m_ViewID)) + DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT + | LVS_SINGLESEL | LVS_NOSORTHEADER | LVS_OWNERDATA; + if (!m_List.Create(dwStyle, CRect(0, 0, 0, 0), this, IDC_MIDI_TARGET_LIST)) return -1; + m_List.SendMessage(WM_SETFONT, WPARAM(GetStockObject(DEFAULT_GUI_FONT))); + // force list to send appropriate notifications for our character size + ListView_SetUnicodeFormat(m_List.m_hWnd, sizeof(TCHAR) == sizeof(WCHAR)); + // increase item height to accomodate popup edit controls; + // temporarily enable checkbox style to get appropriate height + DWORD dwListExStyle = LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT; + m_List.SetExtendedStyle(dwListExStyle | LVS_EX_CHECKBOXES); // add checkbox style + m_List.ModifyStyle(0, LVS_OWNERDRAWFIXED); // add owner draw style + m_List.MoveWindow(0, 0, 0, 1); // force list to send WM_MEASUREITEM + m_List.SetExtendedStyle(dwListExStyle); // remove checkbox style + m_List.MoveWindow(0, 0, 0, 0); // force list to send WM_MEASUREITEM again + m_List.ModifyStyle(LVS_OWNERDRAWFIXED, 0); // remove owner draw style return 0; } BOOL CMidiTargetDlg::OnInitDialog() { CChildDlg::OnInitDialog(); + m_List.CreateColumns(m_ColInfo, COLUMNS); - m_View->CreateCols(COLUMNS, m_ColInfo); - return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } @@ -126,12 +258,105 @@ BOOL CMidiTargetDlg::OnInitDialog() void CMidiTargetDlg::OnSize(UINT nType, int cx, int cy) { CChildDlg::OnSize(nType, cx, cy); - if (m_View != NULL) - m_View->MoveWindow(0, 0, cx, cy); + m_List.MoveWindow(0, 0, cx, cy); +} + +void CMidiTargetDlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + if (nIDCtl == IDC_MIDI_TARGET_LIST) { + if (!m_ListItemHeight) // if retrieving item height + m_ListItemHeight = lpMeasureItemStruct->itemHeight; // save height + else // reapplying saved item height + lpMeasureItemStruct->itemHeight = m_ListItemHeight; // set height + } +} + +void CMidiTargetDlg::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LVITEM& item = pDispInfo->item; + int iItem = item.iItem; + if (item.mask & LVIF_TEXT) { + switch (item.iSubItem) { + case COL_NAME: + _tcsncpy(item.pszText, LDS(m_TargetNameID[iItem]), item.cchTextMax); + break; + case COL_PORT: + _stprintf(item.pszText, _T("%d"), m_Target[iItem].m_Inst.Port); + break; + case COL_CHAN: + _stprintf(item.pszText, _T("%d"), m_Target[iItem].m_Inst.Chan + 1); + break; + case COL_EVENT: + _tcsncpy(item.pszText, CMidiTarget::GetEventTypeName(m_Target[iItem].m_Event), item.cchTextMax); + break; + case COL_CONTROL: + _stprintf(item.pszText, _T("%d"), m_Target[iItem].m_Control); + break; + case COL_RANGE_START: + _stprintf(item.pszText, _T("%g"), m_Target[iItem].m_RangeStart); + break; + case COL_RANGE_END: + _stprintf(item.pszText, _T("%g"), m_Target[iItem].m_RangeEnd); + break; + case COL_VALUE: + _stprintf(item.pszText, _T("%d"), GetShadowValue(iItem)); + break; + default: + NODEFAULTCASE; + } + } +} + +void CMidiTargetDlg::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLVCUSTOMDRAW plvcd = (LPNMLVCUSTOMDRAW)pNMHDR; + switch (plvcd->nmcd.dwDrawStage) { + case CDDS_PREPAINT : + if (theApp.GetMain()->IsMidiLearn()) // if learning MIDI + *pResult = CDRF_NOTIFYITEMDRAW; // request per-item notifications + else + *pResult = 0; + break; + case CDDS_ITEMPREPAINT: + if (plvcd->nmcd.uItemState & CDIS_SELECTED) { // if item selected + plvcd->clrTextBk = MIDI_LEARN_COLOR; // customize item background color + // trick system into using our custom color instead of selection color + plvcd->nmcd.uItemState &= ~CDIS_SELECTED; // clear item's selected flag + } + *pResult = 0; + break; + default: + *pResult = 0; + } +} + +void CMidiTargetDlg::OnContextMenu(CWnd* pWnd, CPoint point) +{ + m_List.FixContextMenuPoint(point); + CMenu menu; + menu.LoadMenu(IDM_MIDI_TARGET_CTX); + CMenu *mp = menu.GetSubMenu(0); + CPersistDlg::UpdateMenu(this, mp); + mp->TrackPopupMenu(0, point.x, point.y, this); } void CMidiTargetDlg::OnMidiLearn() { - if (m_CurSel >= 0) - GetRow(m_CurSel)->UpdateSelection(); + theApp.GetMain()->SendMessage(WM_COMMAND, ID_MIDI_LEARN); // relay to main frame +} + +void CMidiTargetDlg::OnUpdateMidiLearn(CCmdUI *pCmdUI) +{ + pCmdUI->SetCheck(theApp.GetMain()->IsMidiLearn()); +} + +void CMidiTargetDlg::OnMidiTargetReset() +{ + int iSel = m_List.GetSelection(); + if (iSel >= 0) { + m_Target[iSel].Reset(); + OnTargetChange(iSel, 0); + m_List.Invalidate(); + } } diff --git a/MidiTargetDlg.h b/MidiTargetDlg.h index c544f0e..7f043b1 100644 --- a/MidiTargetDlg.h +++ b/MidiTargetDlg.h @@ -9,6 +9,7 @@ rev date comments 00 19nov13 initial version 01 23apr14 define columns via macro + 02 12jun14 refactor to use grid control instead of row view MIDI target dialog @@ -27,24 +28,38 @@ // CMidiTargetDlg dialog #include "ChildDlg.h" -#include "MidiTargetRowDlg.h" - -class CMidiRowView; +#include "GridCtrl.h" class CMidiTargetDlg : public CChildDlg { DECLARE_DYNAMIC(CMidiTargetDlg); // Construction public: - CMidiTargetDlg(int ViewID, CWnd* pParent = NULL); + CMidiTargetDlg(CWnd* pParent = NULL); + +// Constants + enum { + #define MIDITARGETCOLDEF(name, align, width) COL_##name, + #include "MidiTargetColDef.h" + COLUMNS + }; // Attributes + void SetTargets(const int *TargetNameID, int Targets); static UINT GetTemplateID(); int GetCurSel() const; void SetCurSel(int RowIdx); + CMidiTarget& GetTarget(int RowIdx); + +// Operations + void OnLearnChange(); + void UpdateShadowVal(int RowIdx); + void EnableToolTips(BOOL bEnable = TRUE); // Overrideables - virtual void GetTargetToolTip(int RowIdx, int id, NMHDR* pNMHDR); + virtual void OnTargetChange(int RowIdx, int ColIdx); + virtual int GetShadowValue(int RowIdx); + virtual int GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text); // Overrides // ClassWizard generated virtual function overrides @@ -65,35 +80,40 @@ class CMidiTargetDlg : public CChildDlg virtual BOOL OnInitDialog(); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); + afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); afx_msg void OnMidiLearn(); + afx_msg void OnUpdateMidiLearn(CCmdUI *pCmdUI); + afx_msg void OnMidiTargetReset(); //}}AFX_MSG DECLARE_MESSAGE_MAP() // Types + class CTargetGridCtrl : public CGridCtrl { + public: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + virtual CWnd *CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); + virtual void OnItemChange(LPCTSTR Text); + virtual int GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text); + CMidiTargetDlg *m_pParent; + }; // Constants enum { - #define MIDITARGETCOLDEF(name) COL_##name, - #include "MidiTargetColDef.h" - COLUMNS + MIDI_LEARN_COLOR = RGB(0, 255, 0), }; - static const CRowView::COLINFO m_ColInfo[COLUMNS]; + static const CGridCtrl::COL_INFO m_ColInfo[COLUMNS]; + static const int m_ColToolTip[COLUMNS]; // Data members - int m_ViewID; // control ID of row view - CMidiRowView *m_View; // pointer to MIDI row view - int m_CurSel; // currently selected row, or -1 if none + CTargetGridCtrl m_List; // target grid control + CMidiTargetArray m_Target; // array of targets + const int *m_TargetNameID; // pointer to array of target name string IDs + int m_ListItemHeight; // height of list item, in pixels // Helpers - CMidiTargetRowDlg *GetRow(int Idx); - const CMidiTargetRowDlg *GetRow(int Idx) const; -}; - -class CMidiRowView : public CRowView { -protected: - DECLARE_DYNCREATE(CMidiRowView); - virtual CRowDlg *CreateRow(int Idx); - virtual void UpdateRow(int Idx); }; inline UINT CMidiTargetDlg::GetTemplateID() @@ -101,19 +121,19 @@ inline UINT CMidiTargetDlg::GetTemplateID() return(IDD); } -inline CMidiTargetRowDlg *CMidiTargetDlg::GetRow(int Idx) +inline int CMidiTargetDlg::GetCurSel() const { - return((CMidiTargetRowDlg *)m_View->GetRow(Idx)); + return(m_List.GetSelection()); } -inline const CMidiTargetRowDlg *CMidiTargetDlg::GetRow(int Idx) const +inline CMidiTarget& CMidiTargetDlg::GetTarget(int RowIdx) { - return((CMidiTargetRowDlg *)m_View->GetRow(Idx)); + return(m_Target[RowIdx]); } -inline int CMidiTargetDlg::GetCurSel() const +inline void CMidiTargetDlg::EnableToolTips(BOOL bEnable) { - return(m_CurSel); + m_List.EnableToolTips(bEnable); } //{{AFX_INSERT_LOCATION}} diff --git a/MidiTargetRowDlg.cpp b/MidiTargetRowDlg.cpp deleted file mode 100644 index ba43906..0000000 --- a/MidiTargetRowDlg.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyleft 2013 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 19nov13 initial version - 01 23apr14 rename for clarity - - MIDI target row dialog - -*/ - -// MidiTargetRowDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "ChordEase.h" -#include "MainFrm.h" -#include "MidiTargetRowDlg.h" -#include "MidiTargetDlg.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CMidiTargetRowDlg dialog - -IMPLEMENT_DYNAMIC(CMidiTargetRowDlg, CRowDlg); - -const COLORREF CMidiTargetRowDlg::m_SelectionColor = RGB(0, 255, 0); -const CBrush CMidiTargetRowDlg::m_SelectionBrush(m_SelectionColor); - -CMidiTargetRowDlg::CMidiTargetRowDlg(CWnd* pParent /*=NULL*/) - : CRowDlg(IDD, pParent) -{ - //{{AFX_DATA_INIT(CMidiTargetRowDlg) - //}}AFX_DATA_INIT -} - -void CMidiTargetRowDlg::GetTarget(CMidiTarget& Target) const -{ - Target.m_Inst.Port = m_Port.GetIntVal(); - Target.m_Inst.Chan = m_Chan.GetIntVal() - 1; - Target.m_Event = m_Event.GetCurSel(); - Target.m_Control = m_Control.GetIntVal(); - Target.m_RangeStart = float(m_RangeStart.GetVal()); - Target.m_RangeEnd = float(m_RangeEnd.GetVal()); -} - -void CMidiTargetRowDlg::SetTarget(const CMidiTarget& Target) -{ - m_Port.SetVal(Target.m_Inst.Port); - m_Chan.SetVal(Target.m_Inst.Chan + 1); - m_Event.SetCurSel(Target.m_Event); - m_Control.SetVal(Target.m_Control); - m_RangeStart.SetVal(Target.m_RangeStart); - m_RangeEnd.SetVal(Target.m_RangeEnd); -} - -void CMidiTargetRowDlg::SetTargetName(LPCTSTR Name) -{ - m_Name.SetWindowText(Name); -} - -void CMidiTargetRowDlg::UpdateSelection() -{ - Invalidate(); -} - -void CMidiTargetRowDlg::Select() -{ - CWnd *pFocus = GetFocus(); - CWnd *pGoto = &m_Port; // go to first control by default - if (pFocus != NULL) { - CWnd *pParent = pFocus->GetParent(); - if (pParent != NULL && pParent->IsKindOf(RUNTIME_CLASS(CMidiTargetRowDlg))) - pGoto = GetDlgItem(pFocus->GetDlgCtrlID()); - } - GotoDlgCtrl(pGoto); -} - -CMidiTargetDlg *CMidiTargetRowDlg::GetTargetDlg() -{ - return(STATIC_DOWNCAST(CMidiTargetDlg, GetView()->GetParent())); -} - -void CMidiTargetRowDlg::DoDataExchange(CDataExchange* pDX) -{ - CRowDlg::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CMidiTargetRowDlg) - DDX_Control(pDX, IDS_MIDI_TARG_ROW_RANGE_START, m_RangeStart); - DDX_Control(pDX, IDS_MIDI_TARG_ROW_RANGE_END, m_RangeEnd); - DDX_Control(pDX, IDS_MIDI_TARG_ROW_PORT, m_Port); - DDX_Control(pDX, IDS_MIDI_TARG_ROW_NAME, m_Name); - DDX_Control(pDX, IDS_MIDI_TARG_ROW_EVENT, m_Event); - DDX_Control(pDX, IDS_MIDI_TARG_ROW_CONTROL, m_Control); - DDX_Control(pDX, IDS_MIDI_TARG_ROW_CHAN, m_Chan); - //}}AFX_DATA_MAP -} - -BEGIN_MESSAGE_MAP(CMidiTargetRowDlg, CRowDlg) - //{{AFX_MSG_MAP(CMidiTargetRowDlg) - ON_WM_CTLCOLOR() - ON_BN_CLICKED(IDS_MIDI_TARG_ROW_NAME, OnClickName) - ON_WM_LBUTTONDOWN() - //}}AFX_MSG_MAP - ON_NOTIFY_RANGE(NEN_CHANGED, 0, USHRT_MAX, OnChangedNumEdit) - ON_CONTROL_RANGE(CBN_SELCHANGE, 0, USHRT_MAX, OnSelChangeCombo) - ON_CONTROL_RANGE(EN_KILLFOCUS, 0, USHRT_MAX, OnCtrlKillFocus) - ON_CONTROL_RANGE(BN_KILLFOCUS, 0, USHRT_MAX, OnCtrlKillFocus) - ON_CONTROL_RANGE(CBN_KILLFOCUS, 0, USHRT_MAX, OnCtrlKillFocus) - ON_CONTROL_RANGE(EN_SETFOCUS, 0, USHRT_MAX, OnCtrlSetFocus) - ON_CONTROL_RANGE(BN_SETFOCUS, 0, USHRT_MAX, OnCtrlSetFocus) - ON_CONTROL_RANGE(CBN_SETFOCUS, 0, USHRT_MAX, OnCtrlSetFocus) - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNeedText) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CMidiTargetRowDlg message handlers - -BOOL CMidiTargetRowDlg::OnInitDialog() -{ - CRowDlg::OnInitDialog(); - - EnableToolTips(); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CMidiTargetRowDlg::OnChangedNumEdit(UINT nID, NMHDR* pNMHDR, LRESULT* pResult) -{ - GetNotifyWnd()->SendMessage(UWM_MIDIROWEDIT, m_RowIdx, nID); - *pResult = 0; -} - -void CMidiTargetRowDlg::OnSelChangeCombo(UINT nID) -{ - GetNotifyWnd()->SendMessage(UWM_MIDIROWEDIT, m_RowIdx, nID); -} - -BOOL CMidiTargetRowDlg::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message >= WM_KEYFIRST || pMsg->message <= WM_KEYLAST) { - if (AfxGetMainWnd()->SendMessage(UWM_HANDLEDLGKEY, (WPARAM)pMsg)) - return(TRUE); - } - return CRowDlg::PreTranslateMessage(pMsg); -} - -HBRUSH CMidiTargetRowDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH hbr = CRowDlg::OnCtlColor(pDC, pWnd, nCtlColor); - if ((pWnd == &m_Name || nCtlColor == CTLCOLOR_DLG) // if caption or dialog - && theApp.GetMain()->IsMidiLearn() // and we're learning MIDI assignments - && GetTargetDlg()->GetCurSel() == m_RowIdx) { // and we're selected target - pDC->SetBkColor(m_SelectionColor); // set selection background color - return static_cast(m_SelectionBrush); // return selection brush - } - return hbr; -} - -void CMidiTargetRowDlg::OnCtrlSetFocus(UINT nID) -{ - GetTargetDlg()->SetCurSel(m_RowIdx); // notify target dialog -} - -void CMidiTargetRowDlg::OnCtrlKillFocus(UINT nID) -{ - CWnd *pWnd = GetFocus(); - if (pWnd != NULL && !IsChild(pWnd)) // if newly focused control isn't ours - GetTargetDlg()->SetCurSel(-1); // notify target dialog -} - -void CMidiTargetRowDlg::OnClickName() -{ - Select(); -} - -void CMidiTargetRowDlg::OnLButtonDown(UINT nFlags, CPoint point) -{ - Select(); - CRowDlg::OnLButtonDown(nFlags, point); -} - -BOOL CMidiTargetRowDlg::OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - // if tool is for target name, allow derived dialog to override tip - UINT nID = ::GetDlgCtrlID(HWND(pNMHDR->idFrom)); - if (nID == IDS_MIDI_TARG_ROW_NAME) - GetTargetDlg()->GetTargetToolTip(m_RowIdx, id, pNMHDR); - return theApp.OnToolTipNeedText(id, pNMHDR, pResult); -} diff --git a/MidiTargetRowDlg.h b/MidiTargetRowDlg.h deleted file mode 100644 index 63dedb9..0000000 --- a/MidiTargetRowDlg.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyleft 2013 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 19nov13 initial version - 01 23apr14 rename for clarity - - MIDI target row dialog - -*/ - -#if !defined(AFX_MIDIROWDLG_H__A2704F05_FC3B_4FF6_AAEF_9A1FB2527928__INCLUDED_) -#define AFX_MIDIROWDLG_H__A2704F05_FC3B_4FF6_AAEF_9A1FB2527928__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// MidiTargetRowDlg.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CMidiTargetRowDlg dialog - -#include "RowDlg.h" -#include "SpinNumEdit.h" -#include "MidiTarget.h" - -class CMidiTargetDlg; - -class CMidiTargetRowDlg : public CRowDlg -{ - DECLARE_DYNAMIC(CMidiTargetRowDlg); -// Construction -public: - CMidiTargetRowDlg(CWnd* pParent = NULL); - -// Attributes - void GetTarget(CMidiTarget& Target) const; - void SetTarget(const CMidiTarget& Target); - void SetTargetName(LPCTSTR Name); - -// Operations - void UpdateSelection(); - void Select(); - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CMidiTargetRowDlg) - public: - virtual BOOL PreTranslateMessage(MSG* pMsg); - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: -// Generated message map functions - //{{AFX_MSG(CMidiTargetRowDlg) - virtual BOOL OnInitDialog(); - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - afx_msg void OnClickName(); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - //}}AFX_MSG - afx_msg void OnChangedNumEdit(UINT nID, NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnSelChangeCombo(UINT nID); - afx_msg void OnCtrlKillFocus(UINT nID); - afx_msg void OnCtrlSetFocus(UINT nID); - afx_msg BOOL OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult); - DECLARE_MESSAGE_MAP() - -// Dialog Data - //{{AFX_DATA(CMidiTargetRowDlg) - enum { IDD = IDD_MIDI_TARGET_ROW }; - CNumEdit m_RangeStart; - CNumEdit m_RangeEnd; - CPortEdit m_Port; - CStatic m_Name; - CComboBox m_Event; - CMidiValEdit m_Control; - CChannelEdit m_Chan; - //}}AFX_DATA - -// Constants - static const COLORREF m_SelectionColor; - static const CBrush m_SelectionBrush; - -// Helpers - CMidiTargetDlg *GetTargetDlg(); -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_MIDIROWDLG_H__A2704F05_FC3B_4FF6_AAEF_9A1FB2527928__INCLUDED_) diff --git a/Part.cpp b/Part.cpp index f686744..577197f 100644 --- a/Part.cpp +++ b/Part.cpp @@ -32,6 +32,7 @@ CPart::CPart() { #define PARTDEF(name, init) m_##name = init; #include "PartDef.h" // generate code to initialize members + ZeroMemory(m_MidiShadow, sizeof(m_MidiShadow)); } void CPart::Copy(const CPart& Part) @@ -39,6 +40,7 @@ void CPart::Copy(const CPart& Part) #define PARTDEF(name, init) m_##name = Part.m_##name; #include "PartDef.h" // generate code to copy members CopyMemory(m_MidiTarget, Part.m_MidiTarget, sizeof(m_MidiTarget)); // copy MIDI targets + CopyMemory(m_MidiShadow, Part.m_MidiShadow, sizeof(m_MidiShadow)); } bool CPart::operator==(const CPart& Part) const diff --git a/Part.h b/Part.h index 7709eb4..2bad7a2 100644 --- a/Part.h +++ b/Part.h @@ -123,6 +123,7 @@ class CBasePart { // binary copy OK BASS m_Bass; // bass settings AUTO m_Auto; // auto settings CMidiTarget m_MidiTarget[MIDI_TARGETS]; // array of MIDI targets + char m_MidiShadow[MIDI_TARGETS]; // MIDI controller value for each target }; class CPart : public WObject, public CBasePart { diff --git a/PartMidiTargetDef.h b/PartMidiTargetDef.h index cbf7f87..cfabad1 100644 --- a/PartMidiTargetDef.h +++ b/PartMidiTargetDef.h @@ -26,6 +26,7 @@ PARTMIDITARGETDEF( IN_CC_NOTE_VEL, Input) PARTMIDITARGETDEF( OUT_PATCH, Output) PARTMIDITARGETDEF( OUT_VOLUME, Output) PARTMIDITARGETDEF( OUT_ANTICIPATION, Output) +PARTMIDITARGETDEF( OUT_FIX_HELD_NOTES, Output) PARTMIDITARGETDEF( LEAD_HARM_INTERVAL, Lead) PARTMIDITARGETDEF( LEAD_HARM_OMIT_MELODY, Lead) PARTMIDITARGETDEF( LEAD_HARM_STATIC_MIN, Lead) diff --git a/PartMidiTargetDlg.cpp b/PartMidiTargetDlg.cpp index 424d6a1..7032b3b 100644 --- a/PartMidiTargetDlg.cpp +++ b/PartMidiTargetDlg.cpp @@ -9,6 +9,7 @@ rev date comments 00 19nov13 initial version 01 25may14 override target name tool tip + 02 12jun14 refactor to use grid control instead of row view part MIDI target dialog @@ -33,13 +34,13 @@ static char THIS_FILE[] = __FILE__; IMPLEMENT_DYNAMIC(CPartMidiTargetDlg, CMidiTargetDlg); -const int CPartMidiTargetDlg::m_TargetTipID[] = { +const int CPartMidiTargetDlg::m_TargetCtrlID[] = { #define PARTMIDITARGETDEF(name, page) IDC_PART_##name, #include "PartMidiTargetDef.h" }; CPartMidiTargetDlg::CPartMidiTargetDlg(CWnd* pParent /*=NULL*/) - : CMidiTargetDlg(IDC_PART_MIDI_ROW, pParent) + : CMidiTargetDlg(pParent) { //{{AFX_DATA_INIT(CPartMidiTargetDlg) //}}AFX_DATA_INIT @@ -48,26 +49,55 @@ CPartMidiTargetDlg::CPartMidiTargetDlg(CWnd* pParent /*=NULL*/) void CPartMidiTargetDlg::GetPart(CPart& Part) const { for (int iTarg = 0; iTarg < CPart::MIDI_TARGETS; iTarg++) // for each target - GetRow(iTarg)->GetTarget(Part.m_MidiTarget[iTarg]); // retrieve data from row + Part.m_MidiTarget[iTarg] = m_Target[iTarg]; // retrieve data from row } void CPartMidiTargetDlg::SetPart(const CPart& Part) { for (int iTarg = 0; iTarg < CPart::MIDI_TARGETS; iTarg++) // for each target - GetRow(iTarg)->SetTarget(Part.m_MidiTarget[iTarg]); // update row from data + m_Target[iTarg] = Part.m_MidiTarget[iTarg]; // update row from data + m_List.Invalidate(); } -void CPartMidiTargetDlg::GetTargetToolTip(int RowIdx, int id, NMHDR* pNMHDR) +void CPartMidiTargetDlg::OnTargetChange(int RowIdx, int ColIdx) { - ASSERT(RowIdx >= 0 && RowIdx < _countof(m_TargetTipID)); - int nTipID = m_TargetTipID[RowIdx]; - if (nTipID) { // if alternate tip specified - TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR; - pTTT->uFlags &= ~TTF_IDISHWND; // idFrom is ID, not window handle - pNMHDR->idFrom = nTipID; // set idFrom to hint resource ID + int iPart = theApp.GetMain()->GetPartsBar().GetCurPart(); + if (CPartsBar::IsValidPartIdx(iPart)) { // if current part is valid + theApp.GetMain()->NotifyEdit( + m_ColInfo[ColIdx].TitleID, UCODE_PART, CUndoable::UE_COALESCE); + CPart part(gEngine.GetPart(iPart)); + GetPart(part); + gEngine.SetPart(iPart, part); } } +int CPartMidiTargetDlg::GetShadowValue(int RowIdx) +{ + int iPart = theApp.GetMain()->GetPartsBar().GetCurPart(); + if (CPartsBar::IsValidPartIdx(iPart)) // if current part is valid + return(gEngine.GetPart(iPart).m_MidiShadow[RowIdx]); + return(0); +} + +int CPartMidiTargetDlg::GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text) +{ + if (pHTI->iSubItem == COL_NAME && pHTI->iItem >= 0) { // if name column and valid row + int nID = GetTargetCtrlID(pHTI->iItem); // get row's control ID + if (nID) // if valid ID + return(nID); + } + return(CMidiTargetDlg::GetToolTipText(pHTI, Text)); +} + +int CPartMidiTargetDlg::FindTargetByCtrlID(int CtrlID) +{ + for (int iTarg = 0; iTarg < CPart::MIDI_TARGETS; iTarg++) { // for each target + if (m_TargetCtrlID[iTarg] == CtrlID) // if control ID found + return(iTarg); + } + return(-1); +} + void CPartMidiTargetDlg::DoDataExchange(CDataExchange* pDX) { CMidiTargetDlg::DoDataExchange(pDX); @@ -81,7 +111,6 @@ void CPartMidiTargetDlg::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CPartMidiTargetDlg, CMidiTargetDlg) //{{AFX_MSG_MAP(CPartMidiTargetDlg) //}}AFX_MSG_MAP - ON_MESSAGE(UWM_MIDIROWEDIT, OnMidiRowEdit) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -91,24 +120,8 @@ BOOL CPartMidiTargetDlg::OnInitDialog() { CMidiTargetDlg::OnInitDialog(); - m_View->CreateRows(CPart::MIDI_TARGETS); - m_View->SetNotifyWnd(this); - for (int iTarg = 0; iTarg < CPart::MIDI_TARGETS; iTarg++) // for each target - GetRow(iTarg)->SetTargetName(LDS(CPart::m_MidiTargetNameID[iTarg])); // set name + SetTargets(CPart::m_MidiTargetNameID, CPart::MIDI_TARGETS); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } - -LRESULT CPartMidiTargetDlg::OnMidiRowEdit(WPARAM wParam, LPARAM lParam) -{ - int iPart = theApp.GetMain()->GetPartsBar().GetCurPart(); - if (CPartsBar::IsValidPartIdx(iPart)) { // if current part is valid - theApp.GetMain()->NotifyEdit(INT64TO32(lParam), - UCODE_PART, CUndoable::UE_COALESCE); - CPart part(gEngine.GetPart(iPart)); - GetPart(part); - gEngine.SetPart(iPart, part); - } - return(0); -} diff --git a/PartMidiTargetDlg.h b/PartMidiTargetDlg.h index 3f411c3..5b4c979 100644 --- a/PartMidiTargetDlg.h +++ b/PartMidiTargetDlg.h @@ -9,6 +9,7 @@ rev date comments 00 19nov13 initial version 01 25may14 override target name tool tip + 02 12jun14 refactor to use grid control instead of row view part MIDI target dialog @@ -40,9 +41,15 @@ class CPartMidiTargetDlg : public CMidiTargetDlg // Attributes void GetPart(CPart& Part) const; void SetPart(const CPart& Part); + static int GetTargetCtrlID(int TargetIdx); + +// Operations + static int FindTargetByCtrlID(int CtrlID); // Overrides - virtual void GetTargetToolTip(int RowIdx, int id, NMHDR* pNMHDR); + virtual void OnTargetChange(int RowIdx, int ColIdx); + virtual int GetShadowValue(int RowIdx); + virtual int GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text); // Overrides // ClassWizard generated virtual function overrides @@ -61,19 +68,24 @@ class CPartMidiTargetDlg : public CMidiTargetDlg //{{AFX_MSG(CPartMidiTargetDlg) virtual BOOL OnInitDialog(); //}}AFX_MSG - afx_msg LRESULT OnMidiRowEdit(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() // Types // Constants - static const int m_TargetTipID[]; // tool tip ID for each target + static const int m_TargetCtrlID[CPart::MIDI_TARGETS]; // control ID for each target // Data members // Helpers }; +inline int CPartMidiTargetDlg::GetTargetCtrlID(int TargetIdx) +{ + ASSERT(TargetIdx >= 0 && TargetIdx < _countof(m_TargetCtrlID)); + return(m_TargetCtrlID[TargetIdx]); +} + //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. diff --git a/PartPageView.h b/PartPageView.h index 9443d09..bdf0bff 100644 --- a/PartPageView.h +++ b/PartPageView.h @@ -58,6 +58,7 @@ class CPartPageView : public CView CDialog *GetPage(int PageIdx); const CDialog *GetPage(int PageIdx) const; CString GetControlCaption(UINT CtrlID) const; + CPartMidiTargetDlg& GetMidiTargetDlg(); // Operations public: @@ -134,6 +135,11 @@ inline void CPartPageView::UpdateCmdUI(BOOL bDisableIfNoHandler) m_TabDlg.UpdateCmdUI(bDisableIfNoHandler); } +inline CPartMidiTargetDlg& CPartPageView::GetMidiTargetDlg() +{ + return(m_MidiTargetDlg); +} + ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} diff --git a/PartsBar.h b/PartsBar.h index 4051843..0ba1c10 100644 --- a/PartsBar.h +++ b/PartsBar.h @@ -71,6 +71,7 @@ class CPartsBar : public CMySizingControlBar CString GetPartName(int PartIdx) const; void SetPartName(int PartIdx, LPCTSTR Name); int GetParentPane(HWND hWnd) const; + CPartMidiTargetDlg& GetMidiTargetDlg(); static bool IsValidPartIdx(int PartIdx); static bool IsValidInsertPos(int PartIdx); @@ -222,6 +223,11 @@ inline CString CPartsBar::GetPartName(int PartIdx) const return(GetListCtrl().GetItemText(PartIdx, CPartsListView::COL_PART_NAME)); } +inline CPartMidiTargetDlg& CPartsBar::GetMidiTargetDlg() +{ + return(m_PageView->GetMidiTargetDlg()); +} + ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} diff --git a/PartsListColDef.h b/PartsListColDef.h new file mode 100644 index 0000000..c471339 --- /dev/null +++ b/PartsListColDef.h @@ -0,0 +1,20 @@ +// Copyleft 2014 Chris Korda +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or any later version. +/* + chris korda + + revision history: + rev date comments + 00 20sep13 initial version + + parts list control column definitions + +*/ + +// name align width +LISTCOLDEF( PART_NAME, LVCFMT_LEFT, 70) +LISTCOLDEF( FUNCTION, LVCFMT_LEFT, 60) + +#undef LISTCOLDEF diff --git a/PartsListCtrl.cpp b/PartsListCtrl.cpp index d47e194..e3c3209 100644 --- a/PartsListCtrl.cpp +++ b/PartsListCtrl.cpp @@ -59,19 +59,46 @@ CWnd *CPartsListCtrl::CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, const RECT& re return CGridCtrl::CreateEditCtrl(Text, dwStyle, rect, pParentWnd, nID); } -void CPartsListCtrl::OnItemChange(int Row, int Col, LPCTSTR Text) +void CPartsListCtrl::OnItemChange(LPCTSTR Text) { ASSERT(m_EditCol == CPartsListView::COL_FUNCTION); CPopupCombo *pCombo = STATIC_DOWNCAST(CPopupCombo, m_EditCtrl); int iFunc = pCombo->FindString(0, Text); - int iPart = theApp.GetMain()->GetPartsBar().GetCurPart(); - ASSERT(iPart >= 0); - theApp.GetMain()->NotifyEdit(IDS_PARTS_COL_FUNCTION, - UCODE_PART, CUndoable::UE_COALESCE); - CPart part(gEngine.GetPart(iPart)); - part.m_Function = iFunc; - gEngine.SetPart(iPart, part); - CGridCtrl::OnItemChange(Row, Col, Text); + if (iFunc >= 0) { // if text found in combo + int iPart = theApp.GetMain()->GetPartsBar().GetCurPart(); + ASSERT(iPart >= 0); + CPart part(gEngine.GetPart(iPart)); + if (iFunc != part.m_Function) { // if value changed + ASSERT(iFunc < CPart::FUNCTIONS); + theApp.GetMain()->NotifyEdit(IDS_PARTS_COL_FUNCTION, + UCODE_PART, CUndoable::UE_COALESCE); + part.m_Function = iFunc; + gEngine.SetPart(iPart, part); + CGridCtrl::OnItemChange(Text); + } + } +} + +int CPartsListCtrl::GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text) +{ + UINT nID; + if (pHTI->iItem >= 0) { // if cursor on list item + switch (pHTI->iSubItem) { + case CPartsListView::COL_PART_NAME: + if (pHTI->flags & LVHT_ONITEMSTATEICON) // if cursor on checkbox + nID = IDC_PART_ENABLE; + else + nID = IDC_PART_NAME; + break; + case CPartsListView::COL_FUNCTION: + nID = IDC_PART_FUNCTION; + break; + default: + nID = 0; + } + } else // cursor not on list item + nID = IDS_PARTS_TIP_LIST; + return(nID); } ///////////////////////////////////////////////////////////////////////////// diff --git a/PartsListCtrl.h b/PartsListCtrl.h index 45a80d4..14cc549 100644 --- a/PartsListCtrl.h +++ b/PartsListCtrl.h @@ -55,7 +55,8 @@ class CPartsListCtrl : public CGridCtrl // Overrides virtual CWnd *CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); - virtual void OnItemChange(int Row, int Col, LPCTSTR Text); + virtual void OnItemChange(LPCTSTR Text); + virtual int GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text); }; ///////////////////////////////////////////////////////////////////////////// diff --git a/PartsListView.cpp b/PartsListView.cpp index 482868d..0fb5d40 100644 --- a/PartsListView.cpp +++ b/PartsListView.cpp @@ -9,6 +9,7 @@ rev date comments 00 20sep13 initial version 01 23apr14 add tooltip support + 02 12jun14 in OnCreate, set font parts list view @@ -34,8 +35,8 @@ static char THIS_FILE[] = __FILE__; IMPLEMENT_DYNCREATE(CPartsListView, CView) const CPartsListCtrl::COL_INFO CPartsListView::m_ColInfo[COLUMNS] = { - {IDS_PARTS_COL_PART_NAME, LVCFMT_LEFT, 70}, - {IDS_PARTS_COL_FUNCTION, LVCFMT_LEFT, 60}, + #define LISTCOLDEF(name, align, width) {IDS_PARTS_COL_##name, align, width}, + #include "PartsListColDef.h" }; const LPCTSTR CPartsListView::m_FunctionName[FUNCTIONS] = { @@ -153,7 +154,6 @@ BEGIN_MESSAGE_MAP(CPartsListView, CView) ON_NOTIFY(NM_RCLICK, IDC_PARTS_LIST, OnListClick) ON_WM_DESTROY() //}}AFX_MSG_MAP - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNeedText) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -163,20 +163,16 @@ int CPartsListView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; - // specify owner draw style, but remove it after list control is created; - // this lets us adjust item height by forcing OnMeasureItem to be called - DWORD style = WS_CHILD | WS_VISIBLE - | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_EDITLABELS - | LVS_NOSORTHEADER | LVS_OWNERDRAWFIXED; + DWORD style = WS_CHILD | WS_VISIBLE | LVS_REPORT + | LVS_SHOWSELALWAYS | LVS_EDITLABELS | LVS_NOSORTHEADER; if (!m_List.Create(style, CRect(0, 0, 0, 0), this, IDC_PARTS_LIST)) return -1; - m_List.ModifyStyle(LVS_OWNERDRAWFIXED, 0); // remove owner draw + m_List.SendMessage(WM_SETFONT, WPARAM(GetStockObject(DEFAULT_GUI_FONT))); DWORD ExStyle = LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES; m_List.SetExtendedStyle(ExStyle); m_List.TrackDropPos(TRUE); m_List.CreateColumns(m_ColInfo, COLUMNS); - m_List.LoadColumnWidths(REG_SETTINGS, RK_PARTS_LIST_CW); - EnableToolTips(); + m_List.LoadColumnWidths(REG_SETTINGS, RK_PARTS_LIST_CW); return 0; } @@ -186,12 +182,6 @@ void CPartsListView::OnDestroy() CView::OnDestroy(); } -void CPartsListView::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) -{ - if (nIDCtl == IDC_PARTS_LIST) - lpMeasureItemStruct->itemHeight += 3; // increase row height for popup editing -} - void CPartsListView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); @@ -267,36 +257,3 @@ void CPartsListView::OnContextMenu(CWnd* pWnd, CPoint point) CMenu *mp = menu.GetSubMenu(0); mp->TrackPopupMenu(0, point.x, point.y, theApp.GetMain()); } - -BOOL CPartsListView::OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - if (!theApp.GetMain()->GetOptions().m_Other.ShowTooltips) // if not showing tooltips - return(FALSE); - CPoint pt; - GetCursorPos(&pt); - m_List.ScreenToClient(&pt); // convert cursor to list's client coords - LVHITTESTINFO hti; - hti.pt = pt; - m_List.SubItemHitTest(&hti); - UINT nID; - if (hti.iItem >= 0) { // if cursor on list item - switch (hti.iSubItem) { - case COL_PART_NAME: - if (hti.flags & LVHT_ONITEMSTATEICON) // if cursor on checkbox - nID = IDC_PART_ENABLE; - else - nID = IDC_PART_NAME; - break; - case COL_FUNCTION: - nID = IDC_PART_FUNCTION; - break; - default: - nID = 0; - } - } else // cursor not on list item - nID = IDS_PARTS_TIP_LIST; - TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR; - pTTT->lpszText = MAKEINTRESOURCE(nID); - pTTT->hinst = AfxGetResourceHandle(); - return(TRUE); -} diff --git a/PartsListView.h b/PartsListView.h index 5942720..8c41a14 100644 --- a/PartsListView.h +++ b/PartsListView.h @@ -48,8 +48,8 @@ class CPartsListView : public CView // Constants enum { // columns - COL_PART_NAME, - COL_FUNCTION, + #define LISTCOLDEF(name, align, width) COL_##name, + #include "PartsListColDef.h" COLUMNS }; enum { // functions @@ -94,11 +94,9 @@ class CPartsListView : public CView afx_msg void OnListItemchanged(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnListEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnListReorder(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); afx_msg void OnDestroy(); //}}AFX_MSG - afx_msg BOOL OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult); DECLARE_MESSAGE_MAP() // Constants diff --git a/Patch.cpp b/Patch.cpp index c259b82..6996ffb 100644 --- a/Patch.cpp +++ b/Patch.cpp @@ -31,12 +31,12 @@ #define RK_MIDI_OUT_PORT_ID _T("MidiOutPortID") const LPCTSTR CBasePatch::m_MidiTargetName[MIDI_TARGETS] = { - #define PATCHMIDITARGETDEF(name, page) _T(#name), + #define PATCHMIDITARGETDEF(name, page, tag) _T(#name), #include "PatchMidiTargetDef.h" // generate table of MIDI target names }; const int CBasePatch::m_MidiTargetNameID[MIDI_TARGETS] = { - #define PATCHMIDITARGETDEF(name, page) IDS_PATCH_MT_##name, + #define PATCHMIDITARGETDEF(name, page, tag) IDS_PATCH_MT_##name, #include "PatchMidiTargetDef.h" // generate table of MIDI target name IDs }; @@ -44,6 +44,7 @@ CPatch::CPatch() { #define PATCHDEF(name, init) m_##name = init; #include "PatchDef.h" // generate code to initialize members + ZeroMemory(m_MidiShadow, sizeof(m_MidiShadow)); } double CBasePatch::GetTempo() const @@ -59,6 +60,7 @@ void CPatch::Copy(const CPatch& Patch) m_Part = Patch.m_Part; // copy part array m_InPortID = Patch.m_InPortID; // copy port ID arrays m_OutPortID = Patch.m_OutPortID; + CopyMemory(m_MidiShadow, Patch.m_MidiShadow, sizeof(m_MidiShadow)); } bool CPatch::operator==(const CPatch& Patch) const diff --git a/Patch.h b/Patch.h index 4853677..de8c826 100644 --- a/Patch.h +++ b/Patch.h @@ -27,7 +27,7 @@ struct CBasePatch { // binary copy OK public: // Constants enum { - #define PATCHMIDITARGETDEF(name, page) MIDI_TARGET_##name, + #define PATCHMIDITARGETDEF(name, page, tag) MIDI_TARGET_##name, #include "PatchMidiTargetDef.h" MIDI_TARGETS, }; @@ -56,6 +56,7 @@ struct CBasePatch { // binary copy OK int m_Transpose; // global transposition, in steps int m_CurPart; // index of current part, or -1 if none CMidiTarget m_MidiTarget[MIDI_TARGETS]; // array of MIDI targets + char m_MidiShadow[MIDI_TARGETS]; // MIDI controller value for each target // Attributes double GetTempo() const; diff --git a/PatchAutoInstDlg.cpp b/PatchAutoInstDlg.cpp deleted file mode 100644 index c3071ac..0000000 --- a/PatchAutoInstDlg.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyleft 2013 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 14sep13 initial version - - patch auto instrument dialog - -*/ - -// PatchAutoInstDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "ChordEase.h" -#include "PatchAutoInstDlg.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CPatchAutoInstDlg dialog - -IMPLEMENT_DYNAMIC(CPatchAutoInstDlg, CPatchPageDlg); - -CPatchAutoInstDlg::CPatchAutoInstDlg(CWnd* pParent /*=NULL*/) - : CPatchPageDlg(IDD, pParent) -{ - //{{AFX_DATA_INIT(CPatchAutoInstDlg) - //}}AFX_DATA_INIT -} - -void CPatchAutoInstDlg::GetInst(CBasePatch::AUTO_INST& Inst) const -{ - Inst.Enable = m_Enable.GetCheck() != 0; - Inst.Inst.Port = m_Port.GetIntVal(); - Inst.Inst.Chan = m_Channel.GetIntVal() - 1; - Inst.Velocity = m_Velocity.GetIntVal(); - Inst.Patch = m_Patch.GetIntVal(); - Inst.Volume = m_Volume.GetIntVal(); -} - -void CPatchAutoInstDlg::SetInst(const CBasePatch::AUTO_INST& Inst) -{ - m_Enable.SetCheck(Inst.Enable); - m_Port.SetVal(Inst.Inst.Port); - m_Channel.SetVal(Inst.Inst.Chan + 1); - m_Velocity.SetVal(Inst.Velocity); - m_Patch.SetVal(Inst.Patch); - m_Volume.SetVal(Inst.Volume); -} - -void CPatchAutoInstDlg::DoDataExchange(CDataExchange* pDX) -{ - CPatchPageDlg::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CPatchAutoInstDlg) - DDX_Control(pDX, IDC_PATCH_AINST_PATCH, m_Patch); - DDX_Control(pDX, IDC_PATCH_AINST_VELOCITY, m_Velocity); - DDX_Control(pDX, IDC_PATCH_AINST_PORT, m_Port); - DDX_Control(pDX, IDC_PATCH_AINST_ENABLE, m_Enable); - DDX_Control(pDX, IDC_PATCH_AINST_CHANNEL, m_Channel); - DDX_Control(pDX, IDC_PATCH_AINST_VOLUME, m_Volume); - //}}AFX_DATA_MAP -} - -///////////////////////////////////////////////////////////////////////////// -// CPatchAutoInstDlg message map - -BEGIN_MESSAGE_MAP(CPatchAutoInstDlg, CPatchPageDlg) - //{{AFX_MSG_MAP(CPatchAutoInstDlg) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CPatchAutoInstDlg message handlers - -BOOL CPatchAutoInstDlg::OnInitDialog() -{ - CPatchPageDlg::OnInitDialog(); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} diff --git a/PatchAutoInstDlg.h b/PatchAutoInstDlg.h deleted file mode 100644 index bfd5f8d..0000000 --- a/PatchAutoInstDlg.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyleft 2013 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 14sep13 initial version - - patch auto instrument dialog - -*/ - -#if !defined(AFX_PATCHAUTOINSTDLG_H__F352C13B_F7F1_4873_8524_D86EEB346600__INCLUDED_) -#define AFX_PATCHAUTOINSTDLG_H__F352C13B_F7F1_4873_8524_D86EEB346600__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// PatchAutoInstDlg.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CPatchAutoInstDlg dialog - -#include "PatchPageDlg.h" -#include "NumSpin.h" -#include "NoteEdit.h" - -class CPatch; - -class CPatchAutoInstDlg : public CPatchPageDlg -{ - DECLARE_DYNAMIC(CPatchAutoInstDlg); -// Construction -public: - CPatchAutoInstDlg(CWnd* pParent = NULL); - -// Attributes - static UINT GetTemplateID(); - void GetInst(CBasePatch::AUTO_INST& Inst) const; - void SetInst(const CBasePatch::AUTO_INST& Inst); - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CPatchAutoInstDlg) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: -// Dialog Data - //{{AFX_DATA(CPatchAutoInstDlg) - enum { IDD = IDD_PATCH_METRONOME }; - CPatchEdit m_Patch; - CMidiValEdit m_Velocity; - CPortEdit m_Port; - CButton m_Enable; - CChannelEdit m_Channel; - CPatchEdit m_Volume; - //}}AFX_DATA - -// Generated message map functions - //{{AFX_MSG(CPatchAutoInstDlg) - virtual BOOL OnInitDialog(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -inline UINT CPatchAutoInstDlg::GetTemplateID() -{ - return(IDD); -} - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_PATCHAUTOINSTDLG_H__F352C13B_F7F1_4873_8524_D86EEB346600__INCLUDED_) diff --git a/PatchBar.h b/PatchBar.h index 0e4adc4..3dafe1a 100644 --- a/PatchBar.h +++ b/PatchBar.h @@ -54,6 +54,7 @@ class CPatchBar : public CMySizingControlBar CDialog *GetPage(int PageIdx); const CDialog *GetPage(int PageIdx) const; CString GetControlCaption(UINT CtrlID) const; + CPatchMidiTargetDlg& GetMidiTargetDlg(); // Operations public: @@ -117,6 +118,11 @@ inline void CPatchBar::FocusControl(UINT CtrlID) m_TabDlg.FocusControl(CtrlID); } +inline CPatchMidiTargetDlg& CPatchBar::GetMidiTargetDlg() +{ + return(m_MidiTargetDlg); +} + ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} diff --git a/PatchMetronomeDlg.cpp b/PatchMetronomeDlg.cpp index 94cb561..512a08c 100644 --- a/PatchMetronomeDlg.cpp +++ b/PatchMetronomeDlg.cpp @@ -29,10 +29,10 @@ static char THIS_FILE[] = __FILE__; ///////////////////////////////////////////////////////////////////////////// // CPatchMetronomeDlg dialog -IMPLEMENT_DYNAMIC(CPatchMetronomeDlg, CPatchAutoInstDlg); +IMPLEMENT_DYNAMIC(CPatchMetronomeDlg, CPatchPageDlg); CPatchMetronomeDlg::CPatchMetronomeDlg(CWnd* pParent /*=NULL*/) - : CPatchAutoInstDlg(pParent) + : CPatchPageDlg(IDD, pParent) { //{{AFX_DATA_INIT(CPatchMetronomeDlg) //}}AFX_DATA_INIT @@ -41,7 +41,12 @@ CPatchMetronomeDlg::CPatchMetronomeDlg(CWnd* pParent /*=NULL*/) void CPatchMetronomeDlg::GetPatch(CBasePatch& Patch) const { CBasePatch::METRONOME& Inst = Patch.m_Metronome; - GetInst(Inst); + Inst.Enable = m_Enable.GetCheck() != 0; + Inst.Inst.Port = m_Port.GetIntVal(); + Inst.Inst.Chan = m_Channel.GetIntVal() - 1; + Inst.Velocity = m_Velocity.GetIntVal(); + Inst.Patch = m_Patch.GetIntVal(); + Inst.Volume = m_Volume.GetIntVal(); Inst.Note = m_Note.GetIntVal(); Inst.AccentNote = m_AccentNote.GetIntVal(); Inst.AccentVel = m_AccentVel.GetIntVal(); @@ -51,7 +56,12 @@ void CPatchMetronomeDlg::GetPatch(CBasePatch& Patch) const void CPatchMetronomeDlg::SetPatch(const CBasePatch& Patch) { const CBasePatch::METRONOME& Inst = Patch.m_Metronome; - SetInst(Inst); + m_Enable.SetCheck(Inst.Enable); + m_Port.SetVal(Inst.Inst.Port); + m_Channel.SetVal(Inst.Inst.Chan + 1); + m_Velocity.SetVal(Inst.Velocity); + m_Patch.SetVal(Inst.Patch); + m_Volume.SetVal(Inst.Volume); m_Note.SetVal(Inst.Note); m_AccentNote.SetVal(Inst.AccentNote); m_AccentVel.SetVal(Inst.AccentVel); @@ -60,8 +70,14 @@ void CPatchMetronomeDlg::SetPatch(const CBasePatch& Patch) void CPatchMetronomeDlg::DoDataExchange(CDataExchange* pDX) { - CPatchAutoInstDlg::DoDataExchange(pDX); + CPatchPageDlg::DoDataExchange(pDX); //{{AFX_DATA_MAP(CPatchMetronomeDlg) + DDX_Control(pDX, IDC_PATCH_METRO_PATCH, m_Patch); + DDX_Control(pDX, IDC_PATCH_METRO_VELOCITY, m_Velocity); + DDX_Control(pDX, IDC_PATCH_METRO_PORT, m_Port); + DDX_Control(pDX, IDC_PATCH_METRO_ENABLE, m_Enable); + DDX_Control(pDX, IDC_PATCH_METRO_CHANNEL, m_Channel); + DDX_Control(pDX, IDC_PATCH_METRO_VOLUME, m_Volume); DDX_Control(pDX, IDC_PATCH_METRO_ACCENT_SAME_NOTE, m_AccentSameNote); DDX_Control(pDX, IDC_PATCH_METRO_NOTE, m_Note); DDX_Control(pDX, IDC_PATCH_METRO_ACCENT_NOTE, m_AccentNote); @@ -72,7 +88,7 @@ void CPatchMetronomeDlg::DoDataExchange(CDataExchange* pDX) ///////////////////////////////////////////////////////////////////////////// // CPatchMetronomeDlg message map -BEGIN_MESSAGE_MAP(CPatchMetronomeDlg, CPatchAutoInstDlg) +BEGIN_MESSAGE_MAP(CPatchMetronomeDlg, CPatchPageDlg) //{{AFX_MSG_MAP(CPatchMetronomeDlg) ON_UPDATE_COMMAND_UI(IDC_PATCH_METRO_ACCENT_NOTE, OnUpdateAccentNote) //}}AFX_MSG_MAP @@ -83,7 +99,7 @@ END_MESSAGE_MAP() BOOL CPatchMetronomeDlg::OnInitDialog() { - CPatchAutoInstDlg::OnInitDialog(); + CPatchPageDlg::OnInitDialog(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE diff --git a/PatchMetronomeDlg.h b/PatchMetronomeDlg.h index 0807d09..1ce2003 100644 --- a/PatchMetronomeDlg.h +++ b/PatchMetronomeDlg.h @@ -25,9 +25,9 @@ ///////////////////////////////////////////////////////////////////////////// // CPatchMetronomeDlg dialog -#include "PatchAutoInstDlg.h" +#include "PatchPageDlg.h" -class CPatchMetronomeDlg : public CPatchAutoInstDlg +class CPatchMetronomeDlg : public CPatchPageDlg { DECLARE_DYNAMIC(CPatchMetronomeDlg); // Construction @@ -55,6 +55,12 @@ class CPatchMetronomeDlg : public CPatchAutoInstDlg CSpinNoteEdit m_Note; CSpinNoteEdit m_AccentNote; CMidiValEdit m_AccentVel; + CPatchEdit m_Patch; + CMidiValEdit m_Velocity; + CPortEdit m_Port; + CButton m_Enable; + CChannelEdit m_Channel; + CPatchEdit m_Volume; //}}AFX_DATA // Generated message map functions diff --git a/PatchMidiTargetDef.h b/PatchMidiTargetDef.h index 109d1a4..1374774 100644 --- a/PatchMidiTargetDef.h +++ b/PatchMidiTargetDef.h @@ -13,21 +13,30 @@ */ -// name page -PATCHMIDITARGETDEF( TEMPO, General) -PATCHMIDITARGETDEF( TEMPO_MULTIPLE, General) -PATCHMIDITARGETDEF( TRANSPOSE, General) -PATCHMIDITARGETDEF( LEAD_IN, General) -PATCHMIDITARGETDEF( METRO_ENABLE, Metronome) -PATCHMIDITARGETDEF( METRO_VOLUME, Metronome) -PATCHMIDITARGETDEF( PLAY, General) -PATCHMIDITARGETDEF( PAUSE, General) -PATCHMIDITARGETDEF( REWIND, General) -PATCHMIDITARGETDEF( REPEAT, General) -PATCHMIDITARGETDEF( NEXT_SECTION, General) -PATCHMIDITARGETDEF( NEXT_CHORD, General) -PATCHMIDITARGETDEF( PREV_CHORD, General) -PATCHMIDITARGETDEF( SONG_POSITION, General) +// name page tag +PATCHMIDITARGETDEF( TEMPO, General, _GEN_) +PATCHMIDITARGETDEF( TEMPO_MULTIPLE, General, _GEN_) +PATCHMIDITARGETDEF( TRANSPOSE, General, _GEN_) +PATCHMIDITARGETDEF( LEAD_IN, General, _GEN_) +PATCHMIDITARGETDEF( METRO_ENABLE, Metronome, _) +PATCHMIDITARGETDEF( METRO_VOLUME, Metronome, _) +PATCHMIDITARGETDEF( PLAY, General, _GEN_) +PATCHMIDITARGETDEF( PAUSE, General, _GEN_) +PATCHMIDITARGETDEF( REWIND, General, _GEN_) +PATCHMIDITARGETDEF( REPEAT, General, _GEN_) +PATCHMIDITARGETDEF( NEXT_SECTION, General, _GEN_) +PATCHMIDITARGETDEF( NEXT_CHORD, General, _GEN_) +PATCHMIDITARGETDEF( PREV_CHORD, General, _GEN_) +PATCHMIDITARGETDEF( SONG_POSITION, General, _GEN_) #undef PATCHMIDITARGETDEF +// these targets don't have control IDs +#define IDC_PATCH_GEN_PLAY 0 +#define IDC_PATCH_GEN_PAUSE 0 +#define IDC_PATCH_GEN_REWIND 0 +#define IDC_PATCH_GEN_REPEAT 0 +#define IDC_PATCH_GEN_NEXT_SECTION 0 +#define IDC_PATCH_GEN_NEXT_CHORD 0 +#define IDC_PATCH_GEN_PREV_CHORD 0 +#define IDC_PATCH_GEN_SONG_POSITION 0 diff --git a/PatchMidiTargetDlg.cpp b/PatchMidiTargetDlg.cpp index 7fcf06b..114f810 100644 --- a/PatchMidiTargetDlg.cpp +++ b/PatchMidiTargetDlg.cpp @@ -8,6 +8,7 @@ revision history: rev date comments 00 19nov13 initial version + 01 12jun14 refactor to use grid control instead of row view MIDI target dialog @@ -32,8 +33,13 @@ static char THIS_FILE[] = __FILE__; IMPLEMENT_DYNAMIC(CPatchMidiTargetDlg, CMidiTargetDlg); +const int CPatchMidiTargetDlg::m_TargetCtrlID[] = { + #define PATCHMIDITARGETDEF(name, page, tag) IDC_PATCH##tag##name, + #include "PatchMidiTargetDef.h" +}; + CPatchMidiTargetDlg::CPatchMidiTargetDlg(CWnd* pParent /*=NULL*/) - : CMidiTargetDlg(IDC_MIDI_TARGET, pParent) + : CMidiTargetDlg(pParent) { //{{AFX_DATA_INIT(CPatchMidiTargetDlg) //}}AFX_DATA_INIT @@ -42,13 +48,49 @@ CPatchMidiTargetDlg::CPatchMidiTargetDlg(CWnd* pParent /*=NULL*/) void CPatchMidiTargetDlg::GetPatch(CBasePatch& Patch) const { for (int iTarg = 0; iTarg < CPatch::MIDI_TARGETS; iTarg++) // for each target - GetRow(iTarg)->GetTarget(Patch.m_MidiTarget[iTarg]); // retrieve data from row + Patch.m_MidiTarget[iTarg] = m_Target[iTarg]; // retrieve data from row } void CPatchMidiTargetDlg::SetPatch(const CBasePatch& Patch) { for (int iTarg = 0; iTarg < CPatch::MIDI_TARGETS; iTarg++) // for each target - GetRow(iTarg)->SetTarget(Patch.m_MidiTarget[iTarg]); // update row from data + m_Target[iTarg] = Patch.m_MidiTarget[iTarg]; // update row from data + m_List.Invalidate(); +} + +void CPatchMidiTargetDlg::OnTargetChange(int RowIdx, int ColIdx) +{ + theApp.GetMain()->NotifyEdit( + m_ColInfo[ColIdx].TitleID, UCODE_BASE_PATCH, CUndoable::UE_COALESCE); + CBasePatch patch; + gEngine.GetBasePatch(patch); + GetPatch(patch); + gEngine.SetBasePatch(patch); +} + +int CPatchMidiTargetDlg::GetShadowValue(int RowIdx) +{ + ASSERT(RowIdx >= 0 && RowIdx < CPatch::MIDI_TARGETS); + return(gEngine.GetPatch().m_MidiShadow[RowIdx]); +} + +int CPatchMidiTargetDlg::GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text) +{ + if (pHTI->iSubItem == COL_NAME && pHTI->iItem >= 0) { // if name column and valid row + int nID = GetTargetCtrlID(pHTI->iItem); // get row's control ID + if (nID) // if valid ID + return(nID); + } + return(CMidiTargetDlg::GetToolTipText(pHTI, Text)); +} + +int CPatchMidiTargetDlg::FindTargetByCtrlID(int CtrlID) +{ + for (int iTarg = 0; iTarg < CPatch::MIDI_TARGETS; iTarg++) { // for each target + if (m_TargetCtrlID[iTarg] == CtrlID) // if control ID found + return(iTarg); + } + return(-1); } void CPatchMidiTargetDlg::DoDataExchange(CDataExchange* pDX) @@ -64,7 +106,6 @@ void CPatchMidiTargetDlg::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CPatchMidiTargetDlg, CMidiTargetDlg) //{{AFX_MSG_MAP(CPatchMidiTargetDlg) //}}AFX_MSG_MAP - ON_MESSAGE(UWM_MIDIROWEDIT, OnMidiRowEdit) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -74,22 +115,8 @@ BOOL CPatchMidiTargetDlg::OnInitDialog() { CMidiTargetDlg::OnInitDialog(); - m_View->CreateRows(CPatch::MIDI_TARGETS); - m_View->SetNotifyWnd(this); - for (int iTarg = 0; iTarg < CPatch::MIDI_TARGETS; iTarg++) // for each target - GetRow(iTarg)->SetTargetName(LDS(CPatch::m_MidiTargetNameID[iTarg])); // set name + SetTargets(CPatch::m_MidiTargetNameID, CPatch::MIDI_TARGETS); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } - -LRESULT CPatchMidiTargetDlg::OnMidiRowEdit(WPARAM wParam, LPARAM lParam) -{ - theApp.GetMain()->NotifyEdit(INT64TO32(lParam), - UCODE_BASE_PATCH, CUndoable::UE_COALESCE); - CBasePatch patch; - gEngine.GetBasePatch(patch); - GetPatch(patch); - gEngine.SetBasePatch(patch); - return(0); -} diff --git a/PatchMidiTargetDlg.h b/PatchMidiTargetDlg.h index 7f20965..9d7a6f8 100644 --- a/PatchMidiTargetDlg.h +++ b/PatchMidiTargetDlg.h @@ -8,6 +8,7 @@ revision history: rev date comments 00 19nov13 initial version + 01 12jun14 refactor to use grid control instead of row view MIDI target dialog @@ -39,6 +40,15 @@ class CPatchMidiTargetDlg : public CMidiTargetDlg // Attributes void GetPatch(CBasePatch& Patch) const; void SetPatch(const CBasePatch& Patch); + static int GetTargetCtrlID(int TargetIdx); + +// Operations + static int FindTargetByCtrlID(int CtrlID); + +// Overrides + virtual void OnTargetChange(int RowIdx, int ColIdx); + virtual int GetShadowValue(int RowIdx); + virtual int GetToolTipText(const LVHITTESTINFO* pHTI, CString& Text); // Overrides // ClassWizard generated virtual function overrides @@ -57,18 +67,24 @@ class CPatchMidiTargetDlg : public CMidiTargetDlg //{{AFX_MSG(CPatchMidiTargetDlg) virtual BOOL OnInitDialog(); //}}AFX_MSG - afx_msg LRESULT OnMidiRowEdit(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() // Types // Constants + static const int m_TargetCtrlID[CPatch::MIDI_TARGETS]; // control ID for each target // Data members // Helpers }; +inline int CPatchMidiTargetDlg::GetTargetCtrlID(int TargetIdx) +{ + ASSERT(TargetIdx >= 0 && TargetIdx < _countof(m_TargetCtrlID)); + return(m_TargetCtrlID[TargetIdx]); +} + //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. diff --git a/PatchPageDlg.cpp b/PatchPageDlg.cpp index 3002b0a..eee82da 100644 --- a/PatchPageDlg.cpp +++ b/PatchPageDlg.cpp @@ -9,6 +9,7 @@ rev date comments 00 14sep13 initial version 01 22apr14 add tooltip support + 02 10jun14 add MIDI learn patch page dialog @@ -43,17 +44,70 @@ void CPatchPageDlg::UpdateEngine(UINT CtrlID) gEngine.SetBasePatch(patch); } +void CPatchPageDlg::GetSelectionRect(CWnd *pChild, CRect& rSelect) +{ + enum { + BORDER = 3 // selection border, in pixels + }; + ASSERT(pChild != NULL); + CWnd *pParent = pChild->GetParent(); + ASSERT(pParent != NULL); + if (pParent->IsKindOf(RUNTIME_CLASS(CComboBox))) // if parent is combo box + pChild = pParent; + CRect rSel; + pChild->GetWindowRect(rSel); + if (pChild->IsKindOf(RUNTIME_CLASS(CEdit))) { // if child is edit + CWnd *pNext = pChild->GetNextWindow(); + if (pNext != NULL && pNext->IsKindOf(RUNTIME_CLASS(CSpinButtonCtrl))) { + CRect rSpin; + pNext->GetWindowRect(rSpin); + rSel = rSel | rSpin; // union of edit and spin control rects + } + } + ScreenToClient(rSel); + rSel.InflateRect(BORDER, BORDER); + rSelect = rSel; +} + +void CPatchPageDlg::UpdateMidiLearn(CWnd *pChild) +{ + CRect rSel; + GetSelectionRect(pChild, rSel); + InvalidateRect(rSel); +} + +void CPatchPageDlg::UpdateMidiLearn(UINT nID) +{ + CWnd *pWnd = GetDlgItem(nID); + if (pWnd != NULL) + UpdateMidiLearn(pWnd); +} + +void CPatchPageDlg::UpdateMidiLearn() +{ + CWnd *pWnd = GetFocus(); + if (pWnd != NULL && IsChild(pWnd)) + UpdateMidiLearn(pWnd); +} + ///////////////////////////////////////////////////////////////////////////// // CPatchPageDlg message map BEGIN_MESSAGE_MAP(CPatchPageDlg, CScrollDlg) //{{AFX_MSG_MAP(CPatchPageDlg) + ON_WM_PAINT() //}}AFX_MSG_MAP ON_NOTIFY_RANGE(NEN_CHANGED, 0, USHRT_MAX, OnChangedNumEdit) ON_CONTROL_RANGE(BN_CLICKED, 0, USHRT_MAX, OnClickedBtn) ON_CONTROL_RANGE(CBN_SELCHANGE, 0, USHRT_MAX, OnSelChangeCombo) ON_NOTIFY_RANGE(NCBN_DURATION_CHANGED, 0, USHRT_MAX, OnChangedDurationCombo) ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNeedText) + ON_CONTROL_RANGE(EN_SETFOCUS, 0, USHRT_MAX, OnChildSetFocus) + ON_CONTROL_RANGE(BN_SETFOCUS, 0, USHRT_MAX, OnChildSetFocus) + ON_CONTROL_RANGE(CBN_SETFOCUS, 0, USHRT_MAX, OnChildSetFocus) + ON_CONTROL_RANGE(EN_KILLFOCUS, 0, USHRT_MAX, OnChildKillFocus) + ON_CONTROL_RANGE(BN_KILLFOCUS, 0, USHRT_MAX, OnChildKillFocus) + ON_CONTROL_RANGE(CBN_KILLFOCUS, 0, USHRT_MAX, OnChildKillFocus) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// @@ -95,3 +149,41 @@ BOOL CPatchPageDlg::OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult) { return theApp.OnToolTipNeedText(id, pNMHDR, pResult); } + +void CPatchPageDlg::OnPaint() +{ + if (theApp.GetMain()->IsMidiLearn()) { // if learning MIDI assignments + CPaintDC dc(this); // device context for painting + CWnd *pFocusWnd = GetFocus(); + // if focus window is one of our controls + if (pFocusWnd != NULL && IsChild(pFocusWnd)) { + int iPart; // find MIDI target corresponding to control, if any + int iTarget = theApp.GetMain()->GetCtrlMidiTarget(pFocusWnd, iPart); + if (iTarget < 0) { // if target not found + int nID = pFocusWnd->GetDlgCtrlID(); + if (nID == IDC_PART_IN_PORT || nID == IDC_PART_IN_CHAN) + iTarget = INT_MAX; // input port/channel are special targets + } + if (iTarget >= 0) { // if control mapped to MIDI target + COLORREF cSel = RGB(0, 255, 0); + CRect rSel; + GetSelectionRect(pFocusWnd, rSel); + dc.FillSolidRect(rSel, cSel); // highlight control + } + } + } else { // not learning MIDI assignments + Default(); + } +} + +void CPatchPageDlg::OnChildSetFocus(UINT nID) +{ + if (theApp.GetMain()->IsMidiLearn()) // if learning MIDI assignments + UpdateMidiLearn(nID); +} + +void CPatchPageDlg::OnChildKillFocus(UINT nID) +{ + if (theApp.GetMain()->IsMidiLearn()) // if learning MIDI assignments + UpdateMidiLearn(nID); +} diff --git a/PatchPageDlg.h b/PatchPageDlg.h index 0f99e93..f9623fa 100644 --- a/PatchPageDlg.h +++ b/PatchPageDlg.h @@ -9,6 +9,7 @@ rev date comments 00 14sep13 initial version 01 22apr14 add tooltip support + 02 10jun14 add MIDI learn patch page dialog @@ -41,6 +42,9 @@ class CPatchPageDlg : public CScrollDlg virtual void GetPatch(CBasePatch& Patch) const = 0; virtual void UpdateEngine(UINT CtrlID); +// Operations + void UpdateMidiLearn(); + // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CPatchPageDlg) //}}AFX_VIRTUAL @@ -54,13 +58,21 @@ class CPatchPageDlg : public CScrollDlg // Generated message map functions //{{AFX_MSG(CPatchPageDlg) virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); //}}AFX_MSG afx_msg void OnChangedNumEdit(UINT nID, NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnClickedBtn(UINT nID); afx_msg void OnSelChangeCombo(UINT nID); afx_msg void OnChangedDurationCombo(UINT nID, NMHDR* pNMHDR, LRESULT* pResult); afx_msg BOOL OnToolTipNeedText(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnChildSetFocus(UINT nID); + afx_msg void OnChildKillFocus(UINT nID); DECLARE_MESSAGE_MAP() + +// Helpers + void GetSelectionRect(CWnd *pChild, CRect& rSelect); + void UpdateMidiLearn(CWnd *pChild); + void UpdateMidiLearn(UINT nID); }; ///////////////////////////////////////////////////////////////////////////// diff --git a/PianoDlg.cpp b/PianoDlg.cpp index c02616c..6d1dd04 100644 --- a/PianoDlg.cpp +++ b/PianoDlg.cpp @@ -45,31 +45,6 @@ CPianoDlg::CPianoDlg(CWnd* pParent /*=NULL*/) m_WasShown = FALSE; } -void CPianoDlg::InitNoteCombo(CComboBox& Combo, CIntRange Range, int SelIdx) -{ - CString s; - int iSel = -1; - for (CNote iNote = Range.Start; iNote <= Range.End; iNote++) { - Combo.AddString(iNote.MidiName()); - if (iNote == SelIdx) - iSel = iNote - Range.Start; - } - Combo.SetCurSel(iSel); -} - -void CPianoDlg::InitNumericCombo(CComboBox& Combo, CIntRange Range, int SelIdx) -{ - CString s; - int iSel = -1; - for (int iItem = Range.Start; iItem <= Range.End; iItem++) { - s.Format(_T("%d"), iItem); - Combo.AddString(s); - if (iItem == SelIdx) - iSel = iItem - Range.Start; - } - Combo.SetCurSel(iSel); -} - void CPianoDlg::PlayNote(int Note, bool Enable) { if (Note < 0 || Note > MIDI_NOTE_MAX) // if note outside MIDI range @@ -102,10 +77,10 @@ void CPianoDlg::SavePianoState() void CPianoDlg::InitControls() { - InitNumericCombo(m_PortCombo, CIntRange(0, MAX_PORTS - 1), m_State.Port); - InitNumericCombo(m_ChannelCombo, CIntRange(1, MIDI_CHANNELS), m_State.Channel + 1); - InitNoteCombo(m_StartNoteCombo, CIntRange(0, MIDI_NOTE_MAX), m_State.StartNote); - InitNumericCombo(m_KeyCountCombo, CIntRange(MIN_KEYS, MAX_KEYS), m_State.KeyCount); + CChordEaseApp::InitNumericCombo(m_PortCombo, CIntRange(0, MAX_PORTS - 1), m_State.Port); + CChordEaseApp::InitNumericCombo(m_ChannelCombo, CIntRange(1, MIDI_CHANNELS), m_State.Channel + 1); + CChordEaseApp::InitNoteCombo(m_StartNoteCombo, CIntRange(0, MIDI_NOTE_MAX), m_State.StartNote); + CChordEaseApp::InitNumericCombo(m_KeyCountCombo, CIntRange(MIN_KEYS, MAX_KEYS), m_State.KeyCount); m_VelocitySlider.SetRange(0, MIDI_NOTE_MAX); m_VelocitySlider.SetPos(m_State.Velocity); } diff --git a/PianoDlg.h b/PianoDlg.h index a715b0f..71cb0d0 100644 --- a/PianoDlg.h +++ b/PianoDlg.h @@ -129,8 +129,6 @@ class CPianoDlg : public CModelessDlg // Helpers void PlayNote(int Note, bool Enable); - static void InitNoteCombo(CComboBox& Combo, CIntRange Range, int SelIdx); - static void InitNumericCombo(CComboBox& Combo, CIntRange Range, int SelIdx); void ResetPianoState(); void LoadPianoState(); void SavePianoState(); diff --git a/RecordPlayerDlg.cpp b/RecordPlayerDlg.cpp index 6638e33..050001e 100644 --- a/RecordPlayerDlg.cpp +++ b/RecordPlayerDlg.cpp @@ -60,6 +60,7 @@ CRecordPlayerDlg::CRecordPlayerDlg(CWnd* pParent /*=NULL*/) m_StartPos = 0; m_Duration = 0; m_TrackList.m_pParent = this; + m_TrackList.SetDragEnable(FALSE); } CRecordPlayerDlg::CPlay::CPlay(CRecordPlayerDlg& Dlg, bool Enable) : m_Dlg(Dlg) @@ -353,17 +354,17 @@ CWnd *CRecordPlayerDlg::CTrackList::CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, return CGridCtrl::CreateEditCtrl(Text, dwStyle, rect, pParentWnd, nID); } -void CRecordPlayerDlg::CTrackList::OnItemChange(int Row, int Col, LPCTSTR Text) +void CRecordPlayerDlg::CTrackList::OnItemChange(LPCTSTR Text) { - switch (Col) { + switch (m_EditCol) { case CRecordPlayerDlg::COL_PORT: - m_pParent->SetPort(Row, _ttoi(Text)); + m_pParent->SetPort(m_EditRow, _ttoi(Text)); break; case CRecordPlayerDlg::COL_CHANNEL: - m_pParent->SetChannel(Row, _ttoi(Text) - 1); + m_pParent->SetChannel(m_EditRow, _ttoi(Text) - 1); break; } - CGridCtrl::OnItemChange(Row, Col, Text); + CGridCtrl::OnItemChange(Text); } void CRecordPlayerDlg::DoDataExchange(CDataExchange* pDX) diff --git a/RecordPlayerDlg.h b/RecordPlayerDlg.h index 091c63e..b83f86a 100644 --- a/RecordPlayerDlg.h +++ b/RecordPlayerDlg.h @@ -73,7 +73,7 @@ class CRecordPlayerDlg : public CPersistDlg class CTrackList : public CGridCtrl { public: virtual CWnd *CreateEditCtrl(LPCTSTR Text, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID); - virtual void OnItemChange(int Row, int Col, LPCTSTR Text); + virtual void OnItemChange(LPCTSTR Text); CRecordPlayerDlg *m_pParent; }; diff --git a/RowDlg.cpp b/RowDlg.cpp deleted file mode 100644 index 5b93a4e..0000000 --- a/RowDlg.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyleft 2005 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 13aug05 initial version - 01 12sep05 add row position - 02 11jul07 remove row dialog tab message; use DS_CONTROL instead - 03 24mar09 add hook for dialog key handler - 04 20apr10 refactor - 05 06apr12 add shortcut key to reset column widths - - row dialog base class - -*/ - -// RowDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "Resource.h" -#include "RowDlg.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CRowDlg dialog - -IMPLEMENT_DYNAMIC(CRowDlg, CDialog); - -CRowDlg::CRowDlg(UINT Template, CWnd* pParent /*=NULL*/) - : CDialog(Template, pParent) -{ - //{{AFX_DATA_INIT(CRowDlg) - //}}AFX_DATA_INIT - m_RowIdx = 0; - m_RowPos = 0; -} - -void CRowDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CRowDlg) - //}}AFX_DATA_MAP -} - -BEGIN_MESSAGE_MAP(CRowDlg, CDialog) - //{{AFX_MSG_MAP(CRowDlg) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CRowDlg message handlers - -void CRowDlg::OnOK() -{ -} - -void CRowDlg::OnCancel() -{ -} - -BOOL CRowDlg::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) { - CRowView *pView = GetView(); - CWnd *pAccelWnd; - HACCEL Accel = pView->GetAccel(pAccelWnd); - if (pAccelWnd != NULL) { - if (Accel != NULL) { - if (TranslateAccelerator(pAccelWnd->m_hWnd, Accel, pMsg)) - return(TRUE); - } else { - if (pMsg->message == WM_KEYDOWN // for non-system keys only - && pAccelWnd->SendMessage(UWM_HANDLEDLGKEY, (WPARAM)pMsg)) - return(TRUE); - } - } - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ADD - && (GetKeyState(VK_CONTROL) & GKS_DOWN)) { - pView->ResetColumnWidths(); - return(TRUE); - } - } - // NOTE that the derived row dialog's resource is now assumed to have the - // DS_CONTROL style, which makes a dialog work well as a child of another - // dialog, e.g. by integrating the child dialog's tab layout into the tab - // layout of its parent; in previous versions, the parent handled tabbing - // explicitly, so we detected the tab key here and send a notification. - return CDialog::PreTranslateMessage(pMsg); -} diff --git a/RowDlg.h b/RowDlg.h deleted file mode 100644 index b3a868b..0000000 --- a/RowDlg.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyleft 2005 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 13aug05 initial version - 01 20apr10 refactor - - row dialog base class - -*/ - -#if !defined(AFX_ROWDLG_H__A2704F05_FC3B_4FF6_AAEF_9A1FB2527928__INCLUDED_) -#define AFX_ROWDLG_H__A2704F05_FC3B_4FF6_AAEF_9A1FB2527928__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// RowDlg.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CRowDlg dialog - -#include "RowView.h" - -class CRowDlg : public CDialog -{ - DECLARE_DYNAMIC(CRowDlg); -// Construction -public: - CRowDlg(UINT Template, CWnd* pParent = NULL); - -// Attributes - CRowView *GetView() const; - CWnd *GetNotifyWnd() const; - HACCEL GetAccel(CWnd*& AccelWnd) const; - int GetRowIndex() const; - void SetRowIndex(int Idx); - int GetRowPos() const; - void SetRowPos(int Pos); - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CRowDlg) - public: - virtual BOOL PreTranslateMessage(MSG* pMsg); - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual void OnOK(); - virtual void OnCancel(); - //}}AFX_VIRTUAL - -// Implementation -protected: -// Generated message map functions - //{{AFX_MSG(CRowDlg) - //}}AFX_MSG - DECLARE_MESSAGE_MAP() - -// Dialog Data - //{{AFX_DATA(CRowDlg) - //}}AFX_DATA - -// Member data - int m_RowIdx; // row's index in parent array - int m_RowPos; // row's display position; may differ from index -}; - -inline CRowView *CRowDlg::GetView() const -{ - CWnd *pForm = GetParent(); - ASSERT(DYNAMIC_DOWNCAST(CRowView, pForm->GetParent())); - return((CRowView *)pForm->GetParent()); -} - -inline CWnd *CRowDlg::GetNotifyWnd() const -{ - return(GetView()->GetNotifyWnd()); -} - -inline HACCEL CRowDlg::GetAccel(CWnd*& AccelWnd) const -{ - return(GetView()->GetAccel(AccelWnd)); -} - -inline int CRowDlg::GetRowIndex() const -{ - return(m_RowIdx); -} - -inline void CRowDlg::SetRowIndex(int Idx) -{ - m_RowIdx = Idx; -} - -inline int CRowDlg::GetRowPos() const -{ - return(m_RowPos); -} - -inline void CRowDlg::SetRowPos(int Pos) -{ - m_RowPos = Pos; -} - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_ROWDLG_H__A2704F05_FC3B_4FF6_AAEF_9A1FB2527928__INCLUDED_) diff --git a/RowForm.cpp b/RowForm.cpp deleted file mode 100644 index 2de0a0f..0000000 --- a/RowForm.cpp +++ /dev/null @@ -1,139 +0,0 @@ -// Copyleft 2005 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 17may05 initial version - 01 21jul05 make room for header in CalcWindowRect - 02 07sep05 verify dynamic downcast in CalcWindowRect - 03 22dec06 create dialog bar variant from CRowDialogForm - 04 16jul07 relay keyboard messages to parent - 05 20apr10 refactor - 06 12may11 avoid focus, pass it to parent row view - - row form - -*/ - -// RowForm.cpp : implementation file -// - -#include "stdafx.h" -#include "Resource.h" -#include "RowForm.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CRowForm - -IMPLEMENT_DYNCREATE(CRowForm, CFormView) - -CRowForm::CRowForm() : - CFormView(IDD_ROW_FORM) -{ - //{{AFX_DATA_INIT(CRowForm) - //}}AFX_DATA_INIT -} - -CRowForm::~CRowForm() -{ -} - -BOOL CRowForm::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) -{ - return CFormView::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); -} - -BOOL CRowForm::PreCreateWindow(CREATESTRUCT& cs) -{ - // override default window class styles CS_HREDRAW and CS_VREDRAW - // otherwise resizing frame redraws entire view, causing flicker - CWinApp *pApp = AfxGetApp(); - cs.lpszClass = AfxRegisterWndClass( // create our own window class - CS_DBLCLKS, // request double-clicks - pApp->LoadStandardCursor(IDC_ARROW), // standard cursor - NULL, // no background brush - pApp->LoadIcon(IDR_MAINFRAME)); // app's icon - return CFormView::PreCreateWindow(cs); -} - -void CRowForm::OnDraw(CDC* pDC) -{ - CRect cb; - pDC->GetClipBox(cb); - pDC->FillSolidRect(cb, GetSysColor(COLOR_3DFACE)); -} - -BEGIN_MESSAGE_MAP(CRowForm, CFormView) - //{{AFX_MSG_MAP(CRowForm) - ON_WM_MOUSEACTIVATE() - ON_WM_HSCROLL() - ON_WM_CREATE() - ON_WM_SETFOCUS() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CRowForm diagnostics - -#ifdef _DEBUG -void CRowForm::AssertValid() const -{ - CFormView::AssertValid(); -} - -void CRowForm::Dump(CDumpContext& dc) const -{ - CFormView::Dump(dc); -} -#endif //_DEBUG - -///////////////////////////////////////////////////////////////////////////// -// CRowForm message handlers - -int CRowForm::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (CFormView::OnCreate(lpCreateStruct) == -1) - return -1; - - SetScrollSizes(MM_TEXT, CSize(0, 0)); - - return 0; -} - -int CRowForm::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) -{ - return MA_ACTIVATE; // don't call base class, prevents assertion -} - -void CRowForm::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - GetParent()->PostMessage(WM_HSCROLL, MAKELONG(nSBCode, nPos), NULL); - CFormView::OnHScroll(nSBCode, nPos, pScrollBar); -} - -BOOL CRowForm::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) - GetParent()->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam); - return CFormView::PreTranslateMessage(pMsg); -} - -void CRowForm::OnSetFocus(CWnd* pOldWnd) -{ - // if one of our child row dialogs is deleted while one of its controls - // has focus, we get focus, which causes UI bugs, e.g. opening a recent - // file causes an extra file menu popup; pass focus to parent row view - CWnd *Parent = GetParent(); - if (Parent != NULL) - GetParent()->SetFocus(); -} diff --git a/RowForm.h b/RowForm.h deleted file mode 100644 index cf3dfae..0000000 --- a/RowForm.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyleft 2005 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 17may05 initial version - 01 22dec06 create dialog bar variant from CRowDialogForm - 02 16jul07 relay keyboard messages to parent - 03 20apr10 refactor - 04 12may11 add OnSetFocus - - row form - -*/ - -#if !defined(AFX_ROWFORM_H__F9AB8865_A0D5_49C5_97A9_9A1E2F74BEB1__INCLUDED_) -#define AFX_ROWFORM_H__F9AB8865_A0D5_49C5_97A9_9A1E2F74BEB1__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// RowFormView.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CRowForm form view - -#ifndef __AFXEXT_H__ -#include -#endif - -class CRowForm : public CFormView -{ - DECLARE_DYNCREATE(CRowForm) -// Construction -public: - CRowForm(); - virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); - -// Attributes -public: - -// Operations -public: - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CRowForm) - public: - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - virtual BOOL PreTranslateMessage(MSG* pMsg); - virtual void OnDraw(CDC* pDC); // overridden to draw this view - //}}AFX_VIRTUAL - -// Implementation -protected: - virtual ~CRowForm(); -#ifdef _DEBUG - virtual void AssertValid() const; - virtual void Dump(CDumpContext& dc) const; -#endif - -// Generated message map functions - //{{AFX_MSG(CRowForm) - afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message); - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnSetFocus(CWnd* pOldWnd); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_ROWFORM_H__F9AB8865_A0D5_49C5_97A9_9A1E2F74BEB1__INCLUDED_) diff --git a/RowView.cpp b/RowView.cpp deleted file mode 100644 index 815530d..0000000 --- a/RowView.cpp +++ /dev/null @@ -1,568 +0,0 @@ -// Copyleft 2005 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 15jul05 initial version - 01 21jul05 CreateRows must reposition scroll bars - 02 16aug05 add GetActiveRow, IsTabStop - 03 06sep05 disabled controls can't be tab stops - 04 12sep05 in tab handler, get position from row - 05 17feb06 add ReplaceRows and RemoveAllRows - 06 22dec06 create dialog bar variant from CRowDialog - 07 19jan07 in ReplaceRows, allow zero Rows arg - 08 11jul07 remove OnRowFrameTab - 09 11jul07 in ReplaceRows, replace MoveWindow with SetWindowPos - 10 23nov07 support Unicode - 11 20apr10 refactor - 12 14may11 in CreateCols, fix header column aligment - 13 11nov11 add FixContextMenuPos - 14 11nov11 fix keyboard-triggered context menu - 15 24nov11 add get/set scroll position - 16 21jan12 remove lock window update to fix desktop flicker - 17 21jan12 in CreateRows, scroll before updating row dialogs - 18 31mar12 in MoveRow, make defer pos an argument - 19 06apr12 add column resizing - 20 19nov13 in CreateCols, create row dialog via CreateRow - - row view - -*/ - -// RowView.cpp : implementation file -// - -#include "stdafx.h" -#include "Resource.h" -#include "RowView.h" -#include "RowDlg.h" -#include "RowForm.h" -#include "Persist.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CRowView dialog - -IMPLEMENT_DYNCREATE(CRowView, CView); - -const CRect CRowView::m_Margin(0, 4, 0, 0); - -#define RK_COLUMN_WIDTH _T("CW") // column width registry key suffix - -CRowView::CRowView() -{ - //{{AFX_DATA_INIT(CRowView) - //}}AFX_DATA_INIT - m_Cols = 0; - m_ColInfo = NULL; - m_Form = NULL; - m_TopMargin = 0; - m_HdrHeight = HEADER_HEIGHT; - m_NotifyWnd = NULL; - m_Accel = NULL; - m_AccelWnd = NULL; - m_Reorderable = FALSE; - m_HaveScrollPos = FALSE; - m_ScrollPos = CPoint(0, 0); - m_RowDlgSize = CSize(0, 0); - m_RowFirstCtrlX = 0; - m_RowCtrlCount = 0; -} - -BOOL CRowView::PreCreateWindow(CREATESTRUCT& cs) -{ - // override default window class styles CS_HREDRAW and CS_VREDRAW - // otherwise resizing frame redraws entire view, causing flicker - CWinApp *pApp = AfxGetApp(); - cs.lpszClass = AfxRegisterWndClass( // create our own window class - CS_DBLCLKS, // request double-clicks - pApp->LoadStandardCursor(IDC_ARROW), // standard cursor - NULL, // no background brush - pApp->LoadIcon(IDR_MAINFRAME)); // app's icon - return CView::PreCreateWindow(cs); -} - -bool CRowView::ReadColumnWidths(CColWidthArray& ColWidth) const -{ - int cols = GetCols(); - ColWidth.SetSize(cols); - int nID = GetDlgCtrlID(); - CString s((LPCTSTR)nID); - s += RK_COLUMN_WIDTH; - DWORD ExpectedSize = cols * sizeof(int); - DWORD size = ExpectedSize; - return(CPersist::GetBinary(REG_SETTINGS, s, ColWidth.GetData(), &size) - && size == ExpectedSize); -} - -bool CRowView::WriteColumnWidths() const -{ - int cols = GetCols(); - CColWidthArray ColWidth; - ColWidth.SetSize(cols); - for (int iCol = 0; iCol < cols; iCol++) - ColWidth[iCol] = m_ColState[iCol].CurWidth; - int nID = GetDlgCtrlID(); - CString s((LPCTSTR)nID); - s += RK_COLUMN_WIDTH; - DWORD size = cols * sizeof(int); - return(CPersist::WriteBinary(REG_SETTINGS, s, ColWidth.GetData(), size) != 0); -} - -bool CRowView::CreateCols(int Cols, const COLINFO *ColInfo) -{ - if (Cols <= 0 || m_Cols) - return(FALSE); - // create dummy row before setting m_Cols, so CreateRow method can - // easily identify this case if needed, by testing for m_Cols == 0 - CRowDlg *rp = CreateRow(0); // create dummy row dialog - ASSERT(rp != NULL); - m_ColState.SetSize(Cols); - m_Cols = Cols; - m_ColInfo = ColInfo; - CRect cr, dr; - rp->GetWindowRect(dr); // get row dialog's rectangle - ScreenToClient(dr); - m_RowDlgSize = dr.Size(); - m_RowCtrlCount = Cols; // one row control per column initially - CColWidthArray RegColWidth; - bool HaveRegColWidths = ReadColumnWidths(RegColWidth); - int x = 0; - int TotalCurWidth = 0; - // one extra loop because column widths are set in arrears - for (int iCol = 0; iCol <= Cols; iCol++) { - if (iCol < Cols) { // if not last loop - CWnd *RowCtrl = rp->GetDlgItem(ColInfo[iCol].CtrlID); - RowCtrl->GetWindowRect(cr); - // convert control rectangle to row dialog's coords, not view's, - // else header columns don't line up with controls in some cases - rp->ScreenToClient(cr); // 14may11 added rp - m_ColState[iCol].CtrlInitWidth = cr.Width(); - // if control is an edit control - TCHAR szClassName[16]; - if (GetClassName(RowCtrl->m_hWnd, szClassName, 16) - && !_tcsicmp(szClassName, _T("Edit"))) { - // if next control is a spin control - CWnd *NextCtrl = RowCtrl->GetNextWindow(); - if (NextCtrl != NULL - && GetClassName(NextCtrl->m_hWnd, szClassName, 16) - && !_tcsicmp(szClassName, _T("msctls_updown32"))) { - // only right-aligned spin controls are supported - ASSERT(NextCtrl->GetStyle() & UDS_ALIGNRIGHT); - // spin control requires special handling because it - // doesn't automatically move with its buddy edit control - m_ColState[iCol].SpinCtrlID = NextCtrl->GetDlgCtrlID(); - CRect sr; - NextCtrl->GetWindowRect(sr); - rp->ScreenToClient(sr); - m_ColState[iCol].SpinInitWidth = sr.Width(); - m_RowCtrlCount++; // bump row control count - } - } - } else // last loop - cr.left = dr.Width(); // last column boundary is row dialog width - if (iCol > 0) { // if not first column - int iPrevCol = iCol - 1; - int cx = cr.left - x; // initial default column width - m_ColState[iPrevCol].InitWidth = cx; - if (HaveRegColWidths) - cx = RegColWidth[iPrevCol]; // restore persistent column width - m_ColState[iPrevCol].CurWidth = cx; - TotalCurWidth += cx; - HDITEM item; - item.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH; - CString s((LPCTSTR)ColInfo[iPrevCol].TitleID); - item.pszText = s.GetBuffer(0); - item.fmt = HDF_CENTER; - item.cxy = cx; - m_Hdr.InsertItem(iPrevCol, &item); - x = cr.left; - } else // first column - m_RowFirstCtrlX = cr.left; - } - // compensate row dialog width for non-default column widths - int TotalDeltaWidth = TotalCurWidth - x; - m_RowDlgSize.cx += TotalDeltaWidth; - m_Form->SetScrollSizes(MM_TEXT, CSize(0, 0)); // reset scroll bars - MoveHeader(); // set header's initial position - rp->DestroyWindow(); - delete rp; - return(TRUE); -} - -void CRowView::RemoveAllRows() -{ - if (!m_Row.GetSize()) - return; // nothing to do - for (int iRow = 0; iRow < m_Row.GetSize(); iRow++) { - GetRow(iRow)->DestroyWindow(); - delete GetRow(iRow); - } - m_Row.RemoveAll(); - if (m_Form->m_hWnd) { // dialog may have been destroyed - m_Form->SetScrollSizes(MM_TEXT, CSize(0, 0)); // reset scroll bars - MoveHeader(); // set header's initial position - } -} - -inline void CRowView::MoveRow(HDWP DeferPos, CRowDlg& Row, int Pos) -{ - CPoint sp = m_Form->GetScrollPosition(); // compensate for scroll position - UINT flags = SWP_NOSIZE | SWP_SHOWWINDOW; - DeferWindowPos(DeferPos, Row, HWND_BOTTOM, m_Margin.left - sp.x, - m_Margin.top + Pos * m_RowDlgSize.cy - sp.y, 0, 0, flags); -} - -bool CRowView::CreateRows(int Rows) -{ - if (Rows < 0 || m_Form == NULL) // form must already exist - return(FALSE); - // scroll BEFORE updating row dialogs to avoid painting them prematurely - if (Rows) { - // set view's scrollable area and update scroll bars - CSize ViewArea(m_Margin.left + m_RowDlgSize.cx + m_Margin.right, - m_Margin.top + m_RowDlgSize.cy * Rows + m_Margin.bottom); - m_Form->SetScrollSizes(MM_TEXT, ViewArea); - RepositionBars(0, 0, AFX_IDW_PANE_FIRST, CWnd::reposDefault); - // set window's maximum size - CRect cr; - GetClientRect(cr); - if (m_HaveScrollPos) { // if target scroll position is valid - // compensate scroll position for view area and client rect - m_Form->GetClientRect(cr); - CSize MaxScrollPos( - max(ViewArea.cx - cr.Width(), 0), - max(ViewArea.cy - cr.Height(), 0)); - m_ScrollPos.x = CLAMP(m_ScrollPos.x, 0, MaxScrollPos.cx); - m_ScrollPos.y = CLAMP(m_ScrollPos.y, 0, MaxScrollPos.cy); - m_Form->ScrollToPosition(m_ScrollPos); - m_HaveScrollPos = FALSE; - MoveHeader(); - } - } else - m_Form->SetScrollSizes(MM_TEXT, CSize(0, 0)); - // update and add/delete row dialogs - int PrevRows = GetRows(); - int Updates = min(Rows, PrevRows); - HDWP DeferPos = BeginDeferWindowPos(Rows); // defer positions to reduce flicker - for (int iRow = 0; iRow < Updates; iRow++) { // update existing rows - CRowDlg *rp = GetRow(iRow); - int PrevPos = rp->GetRowPos(); // save row position - UpdateRow(iRow); - int pos = m_Reorderable ? rp->GetRowPos() : iRow; - if (pos != PrevPos) // if row position changed - MoveRow(DeferPos, *rp, pos); - } - if (Rows > PrevRows) { // if adding rows - m_Row.SetSize(Rows); - for (int iRow = PrevRows; iRow < Rows; iRow++) { - CRowDlg *rp = CreateRow(iRow); - if (rp == NULL) - return(FALSE); - m_Row[iRow] = rp; - rp->SetParent(m_Form); // row scrolls with view - rp->SetRowIndex(iRow); - int pos = m_Reorderable ? rp->GetRowPos() : iRow; - MoveRow(DeferPos, *rp, pos); - } - // find first column with non-default width, if any - int iCol; - int nCols = GetCols(); - for (iCol = 0; iCol < nCols; iCol++) { - if (m_ColState[iCol].CurWidth != m_ColState[iCol].InitWidth) - break; - } - if (iCol < nCols) { // if column resizing needed - int width = m_ColState[iCol].CurWidth; - m_ColState[iCol].CurWidth = -1; // spoof no-op test - ResizeColumn(iCol, width, PrevRows); // resize column - } - } else { // deleting rows - for (int iRow = Rows; iRow < PrevRows; iRow++) { - GetRow(iRow)->DestroyWindow(); - delete GetRow(iRow); - } - m_Row.SetSize(Rows); - } - EndDeferWindowPos(DeferPos); - m_HaveScrollPos = FALSE; - return(TRUE); -} - -bool CRowView::CreateRows(int Rows, CPoint ScrollPos) -{ - m_HaveScrollPos = TRUE; - m_ScrollPos = ScrollPos; - return(CreateRows(Rows)); -} - -CPoint CRowView::GetScrollPos() const -{ - return(m_Form->GetScrollPosition()); -} - -CRowDlg *CRowView::CreateRow(int Idx) -{ - return(NULL); -} - -void CRowView::UpdateRow(int Idx) -{ -} - -void CRowView::MoveHeader() -{ - CRect fr, vr; - GetClientRect(fr); - m_Form->GetWindowRect(vr); - ScreenToClient(vr); - fr.left -= m_Form->GetScrollPosition().x; - fr.bottom = vr.top; - fr.top = vr.top - m_HdrHeight; - m_Hdr.MoveWindow(fr); -} - -int CRowView::GetActiveRow() const -{ - CWnd *wp = GetFocus(); - if (wp != NULL) { - int rows = GetRows(); - for (int iRow = 0; iRow < rows; iRow++) { - if (GetRow(iRow)->IsChild(wp)) - return(iRow); - } - } - return(-1); -} - -void CRowView::ResizeColumn(int ColIdx, int Width, int FirstRow) -{ - int rows = GetRows(); - int cols = GetCols(); - if (Width == m_ColState[ColIdx].CurWidth) // if column width unchanged - return; - // build control span array - int x = 0; - CCtrlSpanArray CtrlSpan; - CtrlSpan.SetSize(m_RowCtrlCount); // count includes spin controls - int nCtrls = 0; - int iResizedCtrl = 0; - for (int iCol = 0; iCol < cols; iCol++) { - int cx; - COL_STATE& state = m_ColState[iCol]; - if (iCol == ColIdx) { // if column is resizing - cx = Width; - state.CurWidth = cx; // set column's current width - iResizedCtrl = nCtrls; // save index of resized control - } else // column isn't resizing - cx = state.CurWidth; // use column's current width - CTRL_SPAN span; - if (!iCol) // if first column - span.left = m_RowFirstCtrlX; - else // not first column - span.left = x; - int gutter = state.InitWidth - state.CtrlInitWidth; - span.nID = m_ColInfo[iCol].CtrlID; - span.right = span.left + cx - gutter; - span.right = max(span.right, x); // avoid negative width - CtrlSpan[nCtrls] = span; - nCtrls++; - if (state.SpinCtrlID) { // if control has attached spin control - CTRL_SPAN ss; // add spin control's span to span array - const int SPIN_BUDDY_OVERLAP = 2; - ss.nID = state.SpinCtrlID; - ss.left = span.left + cx - gutter - SPIN_BUDDY_OVERLAP; - ss.right = ss.left + m_ColState[iCol].SpinInitWidth; - ss.left = max(ss.left, span.left); // don't extend beyond buddy - CtrlSpan[nCtrls] = ss; - nCtrls++; - } - x += cx; - } - m_RowDlgSize.cx = x; // update row dialog width - // resize row dialogs and their controls - CRect r; - m_Form->ShowWindow(SW_HIDE); // somewhat reduces flicker - HDWP RowDeferPos = BeginDeferWindowPos(rows); - for (int iRow = FirstRow; iRow < rows; iRow++) { - CWnd *pRow = GetRow(iRow); - HDWP DeferPos = BeginDeferWindowPos(nCtrls - iResizedCtrl); - for (int iCtrl = iResizedCtrl; iCtrl < nCtrls; iCtrl++) { - const CTRL_SPAN& span = CtrlSpan[iCtrl]; - CWnd *pCtrl = pRow->GetDlgItem(span.nID); - pCtrl->GetWindowRect(r); - pRow->ScreenToClient(r); - r.left = span.left; - r.right = span.right; - UINT flags = SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE; - DeferPos = DeferWindowPos(DeferPos, pCtrl->m_hWnd, - NULL, r.left, r.top, r.Width(), r.Height(), flags); -//printf("%d %d %d %d\n", r.left, r.top, r.bottom, r.right); - } - EndDeferWindowPos(DeferPos); - UINT flags = SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE; - RowDeferPos = DeferWindowPos(RowDeferPos, pRow->m_hWnd, - NULL, 0, 0, m_RowDlgSize.cx, m_RowDlgSize.cy, flags); - } - EndDeferWindowPos(RowDeferPos); - m_Form->ShowWindow(SW_SHOW); -} - -void CRowView::SetColumnWidth(int ColIdx, int Width, UINT Flags) -{ - if (Width < 0) // if width is LVSCW_AUTOSIZE - Width = m_ColState[ColIdx].InitWidth; // restore initial width - ResizeColumn(ColIdx, Width); - CSize sz = m_Form->GetTotalSize(); - sz.cx = m_Margin.left + m_RowDlgSize.cx + m_Margin.right; - m_Form->SetScrollSizes(MM_TEXT, sz); - m_Form->UpdateWindow(); // prevents sloppy painting for large row counts - if (Flags & SCW_RESIZE_HEADER) { // if resizing header - int iFirstCol, iLastCol; - if (Flags & SCW_ALL_COLUMNS) { // if resizing all columns - iFirstCol = 0; - iLastCol = GetCols(); - } else { // resize specifed column only - iFirstCol = ColIdx; - iLastCol = ColIdx + 1; - } - for (int iCol = iFirstCol; iCol < iLastCol; iCol++) { - HDITEM item; - item.mask = HDI_WIDTH; - item.cxy = m_ColState[iCol].CurWidth; - m_Hdr.SetItem(iCol, &item); // resize header item to match column - } - } - MoveHeader(); // looks weird but standard behavior, same as list control -} - -void CRowView::ResetColumnWidths() -{ - int cols = GetCols(); - for (int iCol = 1; iCol < cols; iCol++) - m_ColState[iCol].CurWidth = m_ColState[iCol].InitWidth; - m_ColState[0].CurWidth = -1; // spoof no-op test - SetColumnWidth(0, LVSCW_AUTOSIZE, SCW_RESIZE_HEADER | SCW_ALL_COLUMNS); -} - -void CRowView::OnDraw(CDC* pDC) -{ -} - -BEGIN_MESSAGE_MAP(CRowView, CView) - //{{AFX_MSG_MAP(CRowView) - ON_WM_SIZE() - ON_WM_DESTROY() - ON_WM_HSCROLL() - ON_WM_CREATE() - ON_WM_KEYDOWN() - //}}AFX_MSG_MAP - ON_NOTIFY(HDN_ITEMCHANGING, HEADER_ID, OnHdrItemChanging) - ON_NOTIFY(HDN_DIVIDERDBLCLICK, HEADER_ID, OnHdrDividerDblClick) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CRowView message handlers - -int CRowView::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (CView::OnCreate(lpCreateStruct) == -1) - return -1; - - // create form - CRuntimeClass *pFactory = RUNTIME_CLASS(CRowForm); - m_Form = DYNAMIC_DOWNCAST(CRowForm, pFactory->CreateObject()); - if (m_Form == NULL) - return -1; - DWORD dwStyle = WS_CHILD | WS_VISIBLE; - CRect r(0, 0, 0, 0); // arbitrary initial size - if (!m_Form->Create(NULL, NULL, dwStyle, r, this, 0, NULL)) - return -1; - - // create header control - GetClientRect(r); - r.bottom = m_HdrHeight; - m_Hdr.Create(HDS_HORZ | HDS_FULLDRAG, r, this, HEADER_ID); - m_Hdr.SetFont(GetFont()); - m_Hdr.ShowWindow(SW_SHOW); - m_Hdr.SendMessage(WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0); - - return 0; -} - -void CRowView::OnDestroy() -{ - WriteColumnWidths(); - RemoveAllRows(); - CView::OnDestroy(); -} - -void CRowView::OnSize(UINT nType, int cx, int cy) -{ - CView::OnSize(nType, cx, cy); - if (m_Form != NULL) { - CRect r; - GetClientRect(r); - r.top += m_HdrHeight + m_TopMargin; // leave room for header - m_Form->MoveWindow(r); - MoveHeader(); - } -} - -void CRowView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - MoveHeader(); - CView::OnHScroll(nSBCode, nPos, pScrollBar); -} - -bool CRowView::FixContextMenuPos(CPoint& point) const -{ - if (point.x == -1 && point.y == -1) { // if menu triggered via keyboard - CRect r; - CWnd *pWnd = GetFocus(); - int rows = GetRows(); - int i; - for (i = 0; i < rows; i++) { - if (GetRow(i)->IsChild(pWnd)) { // if one of our children has focus - pWnd->GetWindowRect(r); // position menu over child window - break; - } - } - if (i >= rows) // if focused window wasn't one of our children - GetWindowRect(r); // position menu in top left corner of view - point = r.TopLeft() + CSize(10, 10); // offset looks nicer - return(TRUE); - } - return(FALSE); -} - -void CRowView::OnHdrItemChanging(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMHEADER phdr = (LPNMHEADER)pNMHDR; - if (phdr->pitem->mask & HDI_WIDTH) // if width changed - SetColumnWidth(phdr->iItem, phdr->pitem->cxy, 0); // don't resize header - *pResult = 0; -} - -void CRowView::OnHdrDividerDblClick(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMHEADER phdr = (LPNMHEADER)pNMHDR; - SetColumnWidth(phdr->iItem, LVSCW_AUTOSIZE); - *pResult = 0; -} - -void CRowView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - if (nChar == VK_ADD && (GetKeyState(VK_CONTROL) & GKS_DOWN)) - ResetColumnWidths(); - CView::OnKeyDown(nChar, nRepCnt, nFlags); -} diff --git a/RowView.h b/RowView.h deleted file mode 100644 index 0de0531..0000000 --- a/RowView.h +++ /dev/null @@ -1,245 +0,0 @@ -// Copyleft 2005 Chris Korda -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 of the License, or any later version. -/* - chris korda - - revision history: - rev date comments - 00 15jul05 initial version - 01 17feb06 add ReplaceRows and RemoveAllRows - 02 22dec06 create dialog bar variant from CRowDialog - 03 11jul07 remove OnRowFrameTab - 04 23nov07 support Unicode - 05 20apr10 refactor - 06 11nov11 add FixContextMenuPos - 07 24nov11 add get/set scroll position - 08 21jan12 add row dialog size - 09 31mar12 in MoveRow, make defer pos an argument - 10 06apr12 add column resizing - 11 19nov13 in CreateCols, remove RowDlgID argument - - row view - -*/ - -#if !defined(AFX_ROWVIEW_H__53C410DA_1109_40AF_B567_7D7918C63980__INCLUDED_) -#define AFX_ROWVIEW_H__53C410DA_1109_40AF_B567_7D7918C63980__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// RowView.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CRowView dialog - -#include "ArrayEx.h" - -class CRowForm; -class CRowDlg; - -class CRowView : public CView -{ - DECLARE_DYNCREATE(CRowView); -// Construction -public: - CRowView(); - -// Types - typedef struct tagCOLINFO { - int CtrlID; - int TitleID; - } COLINFO; - -// Constants - enum { // set column width flags - SCW_RESIZE_HEADER = 0x01, - SCW_ALL_COLUMNS = 0x02, - }; - -// Attributes - int GetRows() const; - int GetCols() const; - CRowDlg *GetRow(int Idx) const; - CHeaderCtrl& GetHeader(); - int GetHeaderHeight() const; - int GetTopMargin() const; - void SetTopMargin(int Margin); - int GetActiveRow() const; - CWnd *GetNotifyWnd() const; - void SetNotifyWnd(CWnd *Wnd); - HACCEL GetAccel(CWnd*& AccelWnd) const; - void SetAccel(HACCEL Accel, CWnd *AccelWnd); - bool GetReorderable() const; - void SetReorderable(bool Enable); - CPoint GetScrollPos() const; - int GetColumnWidth(int ColIdx) const; - void SetColumnWidth(int ColIdx, int Width, UINT Flags = SCW_RESIZE_HEADER); - -// Operations - bool CreateCols(int Cols, const COLINFO *ColInfo); - bool CreateRows(int Rows); - bool CreateRows(int Rows, CPoint ScrollPos); - void RemoveAllRows(); - bool FixContextMenuPos(CPoint& point) const; - void ResetColumnWidths(); - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CRowView) - public: - virtual void OnDraw(CDC* pDC); // overridden to draw this view - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - //}}AFX_VIRTUAL - -// Implementation -protected: -// Generated message map functions - //{{AFX_MSG(CRowView) - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnDestroy(); - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); - //}}AFX_MSG - afx_msg void OnHdrItemChanging(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnHdrDividerDblClick(NMHDR* pNMHDR, LRESULT* pResult); - DECLARE_MESSAGE_MAP() - -// Types - struct COL_STATE { - int InitWidth; // column's initial width - int CurWidth; // column's current width - int CtrlInitWidth; // initial width of column's control - int SpinCtrlID; // ID of attached spin control, if any - int SpinInitWidth; // initial width of attached spin control - }; - struct CTRL_SPAN { - int nID; // control's resource ID - int left; // span's left coordinate - int right; // span's right coordinate - }; - typedef CArrayEx CRowDlgArray; - typedef CArrayEx CColStateArray; - typedef CArrayEx CCtrlSpanArray; - typedef CArrayEx CColWidthArray; - -// Constants - static const CRect m_Margin; // extra margins around view - enum { - HEADER_ID = 0x1234, // non-zero to distinguish from CListCtrl header - HEADER_HEIGHT = 18, // height of header control, in logical coords - }; - -// Member data - int m_Cols; // number of columns in list - const COLINFO *m_ColInfo; // array of information about each column - CRowForm *m_Form; // pointer to form view, parent of rows - CRowDlgArray m_Row; // array of pointers to row dialogs - CHeaderCtrl m_Hdr; // list's header control - int m_TopMargin; // extra top margin for derived controls - int m_HdrHeight; // height of header control - CWnd *m_NotifyWnd; // notifications are sent to this window - HACCEL m_Accel; // if non-null, row's keyboard accelerators - CWnd *m_AccelWnd; // accelerators are translated by this window - bool m_Reorderable; // true if rows can be reordered - bool m_HaveScrollPos; // true if target scroll position is valid - CPoint m_ScrollPos; // target scroll position if any - CSize m_RowDlgSize; // size of row dialog in client coords - CColStateArray m_ColState; // array of column states - int m_RowFirstCtrlX; // x-coord of row's first control - int m_RowCtrlCount; // total number of controls in row - -// Overridables - virtual CRowDlg *CreateRow(int Idx); - virtual void UpdateRow(int Idx); - -// Overrides - -// Helpers - void MoveHeader(); - void MoveRow(HDWP DeferPos, CRowDlg& Row, int Pos); - void ResizeColumn(int ColIdx, int Width, int FirstRow = 0); - bool ReadColumnWidths(CColWidthArray& ColWidth) const; - bool WriteColumnWidths() const; -}; - -inline int CRowView::GetRows() const -{ - return(m_Row.GetSize()); -} - -inline int CRowView::GetCols() const -{ - return(m_Cols); -} - -inline CRowDlg *CRowView::GetRow(int Idx) const -{ - return((CRowDlg *)m_Row[Idx]); -} - -inline CHeaderCtrl& CRowView::GetHeader() -{ - return(m_Hdr); -} - -inline int CRowView::GetHeaderHeight() const -{ - return(m_HdrHeight); -} - -inline void CRowView::SetTopMargin(int Margin) -{ - m_TopMargin = Margin; -} - -inline int CRowView::GetTopMargin() const -{ - return(m_TopMargin); -} - -inline CWnd *CRowView::GetNotifyWnd() const -{ - return(m_NotifyWnd); -} - -inline void CRowView::SetNotifyWnd(CWnd *Wnd) -{ - m_NotifyWnd = Wnd; -} - -inline HACCEL CRowView::GetAccel(CWnd*& AccelWnd) const -{ - AccelWnd = m_AccelWnd; - return(m_Accel); -} - -inline void CRowView::SetAccel(HACCEL Accel, CWnd *AccelWnd) -{ - m_Accel = Accel; - m_AccelWnd = AccelWnd; -} - -inline bool CRowView::GetReorderable() const -{ - return(m_Reorderable); -} - -inline void CRowView::SetReorderable(bool Enable) -{ - m_Reorderable = Enable; -} - -inline int CRowView::GetColumnWidth(int ColIdx) const -{ - return(m_ColState[ColIdx].CurWidth); -} - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_ROWVIEW_H__53C410DA_1109_40AF_B567_7D7918C63980__INCLUDED_) diff --git a/Song.cpp b/Song.cpp index ad19fbb..36f1826 100644 --- a/Song.cpp +++ b/Song.cpp @@ -355,6 +355,21 @@ int CSong::FindSection(int BeatIdx) const return(m_Section.FindBeat(BeatIdx)); } +int CSong::FindSectionByChord(int ChordIdx) const +{ + return(m_Section.FindBeat(m_StartBeat[ChordIdx])); +} + +bool CSong::IsMergeable(int ChordIdx) const +{ + return((ChordIdx > 0 + && m_Chord[ChordIdx - 1].EqualNoDuration(m_Chord[ChordIdx]) + && FindSectionByChord(ChordIdx - 1) == FindSectionByChord(ChordIdx)) + || (ChordIdx < GetChordCount() - 1 + && m_Chord[ChordIdx + 1].EqualNoDuration(m_Chord[ChordIdx]) + && FindSectionByChord(ChordIdx + 1) == FindSectionByChord(ChordIdx))); +} + void CSong::ClosePrevSection(int Beats) { int PrevEnd; // end of previous section @@ -487,7 +502,7 @@ bool CSong::Read(LPCTSTR Path) return(FALSE); } if (!m_Meter.IsValidMeter()) { // if bogus time signature - ReportError(fp, IDS_SONG_BAD_METER, + ReportError(fp, IDS_SONG_ERR_BAD_METER, m_Meter.m_Numerator, m_Meter.m_Denominator); return(FALSE); } diff --git a/Song.h b/Song.h index f28803d..a04b711 100644 --- a/Song.h +++ b/Song.h @@ -39,8 +39,9 @@ class CSong : public WObject { public: CChord(); CChord(int Duration, CNote Root, CNote Bass, int Type); - bool operator==(const CChord& Chord) const; - bool operator!=(const CChord& Chord) const; + bool operator==(const CChord& Chord) const; + bool operator!=(const CChord& Chord) const; + bool EqualNoDuration(const CChord& Chord) const; int m_Duration; // duration in beats CNote m_Root; // normalized root note CNote m_Bass; // normalized bass note @@ -144,6 +145,8 @@ class CSong : public WObject { const CSection& GetSection(int SectionIdx) const; CString GetSectionName(int SectionIdx) const; int FindSection(int BeatIdx) const; + int FindSectionByChord(int ChordIdx) const; + bool IsMergeable(int ChordIdx) const; void GetProperties(CProperties& Props) const; void SetProperties(const CProperties& Props); CString GetComments() const; @@ -279,6 +282,12 @@ inline bool CSong::CChord::operator!=(const CChord& Chord) const return(!operator==(Chord)); } +inline bool CSong::CChord::EqualNoDuration(const CChord& Chord) const +{ + // binary compare; also assumes duration is first member, followed by root + return(!memcmp(&m_Root, &Chord.m_Root, sizeof(CChord) - sizeof(m_Duration))); +} + inline CSong::CChordInfo::CChordInfo() { } diff --git a/SongState.cpp b/SongState.cpp index b23cd51..a5f4f8e 100644 --- a/SongState.cpp +++ b/SongState.cpp @@ -84,9 +84,8 @@ void CSongState::MergeDuplicateChords() const CSong::CChord& chord = m_Chord[iChord]; CSong::CChord& PrevChord = m_Chord[iChord - 1]; // if chord and previous chord are identical except for duration - if (chord.m_Root == PrevChord.m_Root - && chord.m_Bass == PrevChord.m_Bass - && chord.m_Type == PrevChord.m_Type) { + if (chord.EqualNoDuration(PrevChord) + && m_SectionMap[iChord] == m_SectionMap[iChord - 1]) { // and belong to same section PrevChord.m_Duration += chord.m_Duration; // sum durations RemoveAt(iChord); // delete duplicate chord nChords--; @@ -132,7 +131,7 @@ CIntRange CSongState::FindChordRange(CIntRange BeatRange, CIntRange& Offset) con int CSongState::GetSection(int ChordIdx) { int iSection; - if (ChordIdx < GetChordCount()) // if inserting before end of chord array + if (ChordIdx < GetChordCount()) // if index within chord array iSection = m_SectionMap[ChordIdx]; // return this chord's section else { // inserting at end of chord array if (ChordIdx > 0) // if at least one chord @@ -236,6 +235,17 @@ int CSongState::MoveChords(CIntRange BeatRange, int Beat) return(Beat); // return possibly updated beat } +void CSongState::SetChord(CIntRange BeatRange, const CSong::CChord& Chord) +{ + RemoveChords(BeatRange); + MakeSectionMap(); // must rebuild section map before inserting + CSong::CChordArray ch; + ch.SetSize(1); + ch[0] = Chord; // copy caller's chord + ch[0].m_Duration = BeatRange.LengthInclusive(); // same duration as beat range + InsertChords(BeatRange.Start, ch); // insert chord at start of beat range +} + void CSongState::AssignToSection(CIntRange BeatRange, int SectionIdx) { CIntRange ChordRange, Offset; diff --git a/SongState.h b/SongState.h index cfac50b..9a88a6d 100644 --- a/SongState.h +++ b/SongState.h @@ -33,6 +33,7 @@ class CSongState : public WObject { const CSong::CChord& GetChord(int ChordIdx) const; void GetChords(CSong::CChordArray& Chord) const; void GetChords(CIntRange BeatRange, CSong::CChordArray& Chord) const; + void SetChord(CIntRange BeatRange, const CSong::CChord& Chord); // Operations int FindChord(int Beat, int& Offset) const; diff --git a/Version.h b/Version.h index df4938f..935cf76 100644 --- a/Version.h +++ b/Version.h @@ -66,6 +66,7 @@ 56 18may14 1.0.05.000 57 01jun14 1.0.06.000 58 02jun14 1.0.06.001 + 59 15jun14 1.0.07.000 DON'T FORGET TO CHANGE VERSION RESOURCE diff --git a/res/ChordEase.rc2 b/res/ChordEase.rc2 index f4c564f..33ad91d 100644 --- a/res/ChordEase.rc2 +++ b/res/ChordEase.rc2 @@ -16,8 +16,8 @@ // #define MAJOR_VERSION 1 #define MINOR_VERSION 0 -#define MAJOR_SUBVERSION 6 -#define MINOR_SUBVERSION 1 +#define MAJOR_SUBVERSION 7 +#define MINOR_SUBVERSION 0 ///////////////////////////////////////////////////////////////////////////// diff --git a/resource.h b/resource.h index a251de6..ef289a5 100644 --- a/resource.h +++ b/resource.h @@ -17,36 +17,35 @@ #define IDD_MIDI_ASSIGNS 113 #define IDD_MIDI_EVENT 114 #define IDD_MIDI_NOTE_MAP 115 -#define IDD_MIDI_TARGET_ROW 116 -#define IDD_NOTEPAD 117 -#define IDD_OPT_CHART 118 -#define IDD_OPT_OTHER 119 -#define IDD_OPT_RECORD 120 -#define IDD_PART_AUTO 121 -#define IDD_PART_BASS 122 -#define IDD_PART_COMP 123 -#define IDD_PART_INPUT 124 -#define IDD_PART_LEAD 125 -#define IDD_PART_MIDI 126 -#define IDD_PART_OUTPUT 127 -#define IDD_PATCH_GENERAL 128 -#define IDD_PATCH_METRONOME 129 -#define IDD_PIANO 130 -#define IDD_PROGRESS 131 -#define IDD_RECORD_PLAYER 132 -#define IDD_ROW_FORM 133 -#define IDD_SECTION_LIST 134 -#define IDD_SECTION_PROPS 135 -#define IDD_SONG_PROPS 136 -#define IDD_SPLASH 137 -#define IDD_TABBED 138 -#define IDD_THREADS 139 -#define IDM_CHART_CTX 140 -#define IDM_MIDI_ASSIGNS_CTX 141 -#define IDM_MIDI_EVENT_CTX 142 -#define IDM_OUTPUT_NOTES_CTX 143 -#define IDM_PART_LIST_CTX 144 -#define IDM_PIANO_CTX 145 +#define IDD_NOTEPAD 116 +#define IDD_OPT_CHART 117 +#define IDD_OPT_OTHER 118 +#define IDD_OPT_RECORD 119 +#define IDD_PART_AUTO 120 +#define IDD_PART_BASS 121 +#define IDD_PART_COMP 122 +#define IDD_PART_INPUT 123 +#define IDD_PART_LEAD 124 +#define IDD_PART_MIDI 125 +#define IDD_PART_OUTPUT 126 +#define IDD_PATCH_GENERAL 127 +#define IDD_PATCH_METRONOME 128 +#define IDD_PIANO 129 +#define IDD_PROGRESS 130 +#define IDD_RECORD_PLAYER 131 +#define IDD_SECTION_LIST 132 +#define IDD_SECTION_PROPS 133 +#define IDD_SONG_PROPS 134 +#define IDD_SPLASH 135 +#define IDD_TABBED 136 +#define IDD_THREADS 137 +#define IDM_CHART_CTX 138 +#define IDM_MIDI_ASSIGNS_CTX 139 +#define IDM_MIDI_EVENT_CTX 140 +#define IDM_MIDI_TARGET_CTX 141 +#define IDM_OUTPUT_NOTES_CTX 142 +#define IDM_PART_LIST_CTX 143 +#define IDM_PIANO_CTX 144 #define IDS_APP_ABOUT_TEXT 200 #define IDS_APP_CANT_INIT_COM 201 #define IDS_APP_DEMO_CHECK 202 @@ -64,234 +63,237 @@ #define IDS_CHART_UC_CUT 214 #define IDS_CHART_UC_DELETE 215 #define IDS_CHART_UC_INSERT 216 -#define IDS_CHART_UC_PASTE 217 -#define IDS_CHART_UC_REORDER 218 -#define IDS_CHART_UC_SECTION_CREATE 219 -#define IDS_CHART_UC_SECTION_DELETE 220 -#define IDS_CHART_UC_SECTION_PROPS 221 -#define IDS_CHART_UC_SONG_EDIT 222 -#define IDS_CHART_UC_SONG_PROPS 223 -#define IDS_CHORD_DURATION_OTHER 224 -#define IDS_CKUP_CANT_GET_ADDR 225 -#define IDS_CKUP_CANT_LOAD_DLL 226 -#define IDS_CLIPBOARD_CANT_COPY 227 -#define IDS_CLIPBOARD_CANT_PASTE 228 -#define IDS_COMMON_NO 229 -#define IDS_COMMON_YES 230 -#define IDS_DEVICE_BAR 231 -#define IDS_DEVICE_COL_NAME 232 -#define IDS_DEVICE_COL_PORT 233 -#define IDS_DEVICE_COL_STATE 234 -#define IDS_DEVICE_STATE_CLOSED 235 -#define IDS_DEVICE_STATE_OPEN 236 -#define IDS_EDIT_REDO_FMT 237 -#define IDS_EDIT_UNDO_FMT 238 -#define IDS_ENGERR_CANT_CLOSE_MIDI_IN 239 -#define IDS_ENGERR_CANT_CLOSE_MIDI_OUT 240 -#define IDS_ENGERR_CANT_OPEN_MIDI_IN 241 -#define IDS_ENGERR_CANT_OPEN_MIDI_OUT 242 -#define IDS_ENGERR_CANT_PLAY_STOPPED 243 -#define IDS_ENGERR_CANT_START_MIDI_IN 244 -#define IDS_ENGERR_CREATE_TIMER 245 -#define IDS_ENGERR_CREATE_TIMER_EVENT 246 -#define IDS_ENGERR_CREATE_TIMER_THREAD 247 -#define IDS_ENGERR_DESTROY_TIMER 248 -#define IDS_ENGERR_DESTROY_TIMER_THREAD 249 -#define IDS_ENGERR_RECORDING_TRUNCATED 250 -#define IDS_ENGERR_SET_TIMER_RESOLUTION 251 -#define IDS_ENGERR_START_TIMER_THREAD 252 -#define IDS_ENGERR_STOP_TIMER_THREAD 253 -#define IDS_ENGERR_TOO_MANY_NOTES 254 -#define IDS_ENGINE_MIDI_DEVICE_NONE 255 -#define IDS_ENGMSG_MISSING_DEVICE 256 -#define IDS_HLINK_CANT_LAUNCH 257 -#define IDS_INSCH_BASS_ROOT 258 -#define IDS_INSCH_SELECT_DURATION 259 -#define IDS_MIDI_ASS_COL_CHANNEL 260 -#define IDS_MIDI_ASS_COL_CONTROL 261 -#define IDS_MIDI_ASS_COL_DEVICE 262 -#define IDS_MIDI_ASS_COL_EVENT 263 -#define IDS_MIDI_ASS_COL_PART 264 -#define IDS_MIDI_ASS_COL_PART_NAME 265 -#define IDS_MIDI_ASS_COL_PORT 266 -#define IDS_MIDI_ASS_COL_TARGET 267 -#define IDS_MIDI_EVT_COL_CHANNEL 268 -#define IDS_MIDI_EVT_COL_DEVICE 269 -#define IDS_MIDI_EVT_COL_MESSAGE 270 -#define IDS_MIDI_EVT_COL_P1 271 -#define IDS_MIDI_EVT_COL_P2 272 -#define IDS_MIDI_EVT_COL_PORT 273 -#define IDS_MIDI_EVT_COL_TIMESTAMP 274 -#define IDS_MIDI_EVT_PAUSE 275 -#define IDS_MIDI_FILE_FILTER 276 -#define IDS_MIDI_INPUT_BAR 277 -#define IDS_MIDI_NMAP_COL_ENABLE 278 -#define IDS_MIDI_NMAP_COL_FUNCTION 279 -#define IDS_MIDI_NMAP_COL_IN_CHAN 280 -#define IDS_MIDI_NMAP_COL_IN_DEVICE 281 -#define IDS_MIDI_NMAP_COL_IN_PORT 282 -#define IDS_MIDI_NMAP_COL_OUT_CHAN 283 -#define IDS_MIDI_NMAP_COL_OUT_DEVICE 284 -#define IDS_MIDI_NMAP_COL_OUT_PORT 285 -#define IDS_MIDI_NMAP_COL_PART_INDEX 286 -#define IDS_MIDI_NMAP_COL_PART_NAME 287 -#define IDS_MIDI_NMAP_COL_ZONE_HIGH 288 -#define IDS_MIDI_NMAP_COL_ZONE_LOW 289 -#define IDS_MIDI_OUTPUT_BAR 290 -#define IDS_MIDI_RECORDING_FILTER 291 -#define IDS_MIDI_REC_BAD_FORMAT 292 -#define IDS_MIDI_REC_OUT_OF_ORDER 293 -#define IDS_MIDI_STAT_ACTIVE_SENSING 294 -#define IDS_MIDI_STAT_CHANNEL_WILDCARD 295 -#define IDS_MIDI_STAT_CHAN_AFT 296 -#define IDS_MIDI_STAT_CLOCK 297 -#define IDS_MIDI_STAT_CONTINUE 298 -#define IDS_MIDI_STAT_CONTROL 299 -#define IDS_MIDI_STAT_EOX 300 -#define IDS_MIDI_STAT_KEY_AFT 301 -#define IDS_MIDI_STAT_MTC_QTR_FRAME 302 -#define IDS_MIDI_STAT_NOTE_OFF 303 -#define IDS_MIDI_STAT_NOTE_ON 304 -#define IDS_MIDI_STAT_PATCH 305 -#define IDS_MIDI_STAT_SONG_POSITION 306 -#define IDS_MIDI_STAT_SONG_SELECT 307 -#define IDS_MIDI_STAT_START 308 -#define IDS_MIDI_STAT_STOP 309 -#define IDS_MIDI_STAT_SYSEX 310 -#define IDS_MIDI_STAT_SYSTEM_RESET 311 -#define IDS_MIDI_STAT_SYSTEM_WILDCARD 312 -#define IDS_MIDI_STAT_TUNE_REQUEST 313 -#define IDS_MIDI_STAT_WHEEL 314 -#define IDS_MIDI_TARG_ROW_CHAN 315 -#define IDS_MIDI_TARG_ROW_CONTROL 316 -#define IDS_MIDI_TARG_ROW_EVENT 317 -#define IDS_MIDI_TARG_ROW_NAME 318 -#define IDS_MIDI_TARG_ROW_PORT 319 -#define IDS_MIDI_TARG_ROW_RANGE_END 320 -#define IDS_MIDI_TARG_ROW_RANGE_START 321 -#define IDS_MSGBOX_NO 322 -#define IDS_MSGBOX_YES 323 -#define IDS_MTEVT_CHAN_AFTERTOUCH 324 -#define IDS_MTEVT_CONTROL 325 -#define IDS_MTEVT_NONE 326 -#define IDS_MTEVT_PROGRAM_CHANGE 327 -#define IDS_MTEVT_WHEEL 328 -#define IDS_NOT_APPLICABLE 329 -#define IDS_OPTIONS 330 -#define IDS_OPT_OTHER_DATA_FOLDER 331 -#define IDS_OPT_REC_OUTPUT_FOLDER 332 -#define IDS_OPT_RESET_ALL 333 -#define IDS_OPT_RESTORE_DEFAULTS 334 -#define IDS_OUTPUT_NOTES_BAR 335 -#define IDS_OUT_NOTES_FILTER_ALL 336 -#define IDS_OUT_NOTES_SM_ALL_CHANS 337 -#define IDS_OUT_NOTES_SM_ALL_PORTS 338 -#define IDS_OUT_NOTES_SM_FILTER_CHAN 339 -#define IDS_OUT_NOTES_SM_FILTER_PORT 340 -#define IDS_OUT_NOTES_SM_PIANO_SIZE 341 -#define IDS_PARTS_BAR 342 -#define IDS_PARTS_COL_FUNCTION 343 -#define IDS_PARTS_COL_PART_NAME 344 -#define IDS_PARTS_TIP_LIST 345 -#define IDS_PART_FORMAT 346 -#define IDS_PART_MT_AUTO_PLAY 347 -#define IDS_PART_MT_AUTO_VELOCITY 348 -#define IDS_PART_MT_AUTO_WINDOW 349 -#define IDS_PART_MT_BASS_APPROACH_LENGTH 350 -#define IDS_PART_MT_BASS_APPROACH_TRIGGER 351 -#define IDS_PART_MT_BASS_SLASH_CHORDS 352 -#define IDS_PART_MT_BASS_TARGET_ALIGNMENT 353 -#define IDS_PART_MT_COMP_ARP_ORDER 354 -#define IDS_PART_MT_COMP_ARP_PERIOD 355 -#define IDS_PART_MT_COMP_ARP_PERIOD_QUANT 356 -#define IDS_PART_MT_COMP_ARP_REPEAT 357 -#define IDS_PART_MT_COMP_VARIATION 358 -#define IDS_PART_MT_COMP_VOICING 359 -#define IDS_PART_MT_ENABLE 360 -#define IDS_PART_MT_FUNCTION 361 -#define IDS_PART_MT_IN_CC_NOTE 362 -#define IDS_PART_MT_IN_CC_NOTE_VEL 363 -#define IDS_PART_MT_IN_NON_DIATONIC 364 -#define IDS_PART_MT_IN_TRANSPOSE 365 -#define IDS_PART_MT_IN_VEL_OFFSET 366 -#define IDS_PART_MT_IN_ZONE_HIGH 367 -#define IDS_PART_MT_IN_ZONE_LOW 368 -#define IDS_PART_MT_LEAD_HARM_INTERVAL 369 -#define IDS_PART_MT_LEAD_HARM_OMIT_MELODY 370 -#define IDS_PART_MT_LEAD_HARM_STATIC_MAX 371 -#define IDS_PART_MT_LEAD_HARM_STATIC_MIN 372 -#define IDS_PART_MT_OUT_ANTICIPATION 373 -#define IDS_PART_MT_OUT_PATCH 374 -#define IDS_PART_MT_OUT_VOLUME 375 -#define IDS_PATCH_BAD_FORMAT 376 -#define IDS_PATCH_BAR 377 -#define IDS_PATCH_MT_LEAD_IN 378 -#define IDS_PATCH_MT_METRO_ENABLE 379 -#define IDS_PATCH_MT_METRO_VOLUME 380 -#define IDS_PATCH_MT_NEXT_CHORD 381 -#define IDS_PATCH_MT_NEXT_SECTION 382 -#define IDS_PATCH_MT_PAUSE 383 -#define IDS_PATCH_MT_PLAY 384 -#define IDS_PATCH_MT_PREV_CHORD 385 -#define IDS_PATCH_MT_REPEAT 386 -#define IDS_PATCH_MT_REWIND 387 -#define IDS_PATCH_MT_SONG_POSITION 388 -#define IDS_PATCH_MT_TEMPO 389 -#define IDS_PATCH_MT_TEMPO_MULTIPLE 390 -#define IDS_PATCH_MT_TRANSPOSE 391 -#define IDS_RECORD_AS 392 -#define IDS_RECORD_LOCKED 393 -#define IDS_REC_PLAY_COL_CHANNEL 394 -#define IDS_REC_PLAY_COL_DEVICE 395 -#define IDS_REC_PLAY_COL_EVENTS 396 -#define IDS_REC_PLAY_COL_NAME 397 -#define IDS_REC_PLAY_COL_PORT 398 -#define IDS_REC_PLAY_STOP_PLAYING 399 -#define IDS_REC_PLAY_STOP_RECORDING 400 -#define IDS_SECTION_NAME_SPACES 401 -#define IDS_SEC_LIST_COL_IMPLICIT 402 -#define IDS_SEC_LIST_COL_INDEX 403 -#define IDS_SEC_LIST_COL_LENGTH 404 -#define IDS_SEC_LIST_COL_NAME 405 -#define IDS_SEC_LIST_COL_REPEAT 406 -#define IDS_SEC_LIST_COL_START 407 -#define IDS_SONG_BAD_METER 408 -#define IDS_SONG_ERR_BAD_BASS_NOTE 409 -#define IDS_SONG_ERR_BAD_CHORD 410 -#define IDS_SONG_ERR_BAD_CHORD_TYPE 411 -#define IDS_SONG_ERR_BAD_COMMAND 412 -#define IDS_SONG_ERR_BAD_DURATION 413 -#define IDS_SONG_ERR_BAD_KEY 414 -#define IDS_SONG_ERR_BAD_MODE 415 -#define IDS_SONG_ERR_BAD_ROOT 416 -#define IDS_SONG_ERR_BAD_SCALE 417 -#define IDS_SONG_ERR_BAD_SYNTAX 418 -#define IDS_SONG_ERR_BAD_TEMPO 419 -#define IDS_SONG_ERR_CHORD_TONE_RANGE 420 -#define IDS_SONG_ERR_DUP_CHORD_TYPE 421 -#define IDS_SONG_ERR_READ 422 -#define IDS_SONG_ERR_SEC_BAD_REPEAT 423 -#define IDS_SONG_ERR_SEC_BAD_SYNTAX 424 -#define IDS_SONG_ERR_SEC_CANT_NEST 425 -#define IDS_SONG_ERR_SEC_UNTERMINATED 426 -#define IDS_THREADS_COL_KERNEL_TIME 427 -#define IDS_THREADS_COL_PRIORITY 428 -#define IDS_THREADS_COL_THREAD_ID 429 -#define IDS_THREADS_COL_USER_TIME 430 -#define IDS_UC_BASE_PATCH 431 -#define IDS_UC_CUT 432 -#define IDS_UC_DELETE 433 -#define IDS_UC_ENABLE_PART 434 -#define IDS_UC_INSERT 435 -#define IDS_UC_MIDI_CHASE 436 -#define IDS_UC_MIDI_TARGETS 437 -#define IDS_UC_PART 438 -#define IDS_UC_PASTE 439 -#define IDS_UC_RENAME 440 -#define IDS_UC_REORDER 441 -#define IDS_UC_SELECT_PART 442 -#define IDS_UC_SELECT_PART_PAGE 443 -#define IDS_UC_SELECT_PATCH_PAGE 444 +#define IDS_CHART_UC_MULTI_CHORD_EDIT 217 +#define IDS_CHART_UC_PASTE 218 +#define IDS_CHART_UC_REORDER 219 +#define IDS_CHART_UC_SECTION_CREATE 220 +#define IDS_CHART_UC_SECTION_DELETE 221 +#define IDS_CHART_UC_SECTION_PROPS 222 +#define IDS_CHART_UC_SONG_EDIT 223 +#define IDS_CHART_UC_SONG_PROPS 224 +#define IDS_CHORD_DURATION_OTHER 225 +#define IDS_CKUP_CANT_GET_ADDR 226 +#define IDS_CKUP_CANT_LOAD_DLL 227 +#define IDS_CLIPBOARD_CANT_COPY 228 +#define IDS_CLIPBOARD_CANT_PASTE 229 +#define IDS_COMMON_NO 230 +#define IDS_COMMON_YES 231 +#define IDS_DEVICE_BAR 232 +#define IDS_DEVICE_COL_NAME 233 +#define IDS_DEVICE_COL_PORT 234 +#define IDS_DEVICE_COL_STATE 235 +#define IDS_DEVICE_STATE_CLOSED 236 +#define IDS_DEVICE_STATE_OPEN 237 +#define IDS_EDIT_REDO_FMT 238 +#define IDS_EDIT_UNDO_FMT 239 +#define IDS_ENGERR_CANT_CLOSE_MIDI_IN 240 +#define IDS_ENGERR_CANT_CLOSE_MIDI_OUT 241 +#define IDS_ENGERR_CANT_OPEN_MIDI_IN 242 +#define IDS_ENGERR_CANT_OPEN_MIDI_OUT 243 +#define IDS_ENGERR_CANT_PLAY_STOPPED 244 +#define IDS_ENGERR_CANT_START_MIDI_IN 245 +#define IDS_ENGERR_CREATE_TIMER 246 +#define IDS_ENGERR_CREATE_TIMER_EVENT 247 +#define IDS_ENGERR_CREATE_TIMER_THREAD 248 +#define IDS_ENGERR_DESTROY_TIMER 249 +#define IDS_ENGERR_DESTROY_TIMER_THREAD 250 +#define IDS_ENGERR_RECORDING_TRUNCATED 251 +#define IDS_ENGERR_SET_TIMER_RESOLUTION 252 +#define IDS_ENGERR_START_TIMER_THREAD 253 +#define IDS_ENGERR_STOP_TIMER_THREAD 254 +#define IDS_ENGERR_TOO_MANY_NOTES 255 +#define IDS_ENGINE_MIDI_DEVICE_NONE 256 +#define IDS_ENGMSG_MISSING_DEVICE 257 +#define IDS_HLINK_CANT_LAUNCH 258 +#define IDS_INSCH_BASS_ROOT 259 +#define IDS_INSCH_SELECT_DURATION 260 +#define IDS_MIDI_ASS_COL_CHANNEL 261 +#define IDS_MIDI_ASS_COL_CONTROL 262 +#define IDS_MIDI_ASS_COL_DEVICE 263 +#define IDS_MIDI_ASS_COL_EVENT 264 +#define IDS_MIDI_ASS_COL_PART 265 +#define IDS_MIDI_ASS_COL_PART_NAME 266 +#define IDS_MIDI_ASS_COL_PORT 267 +#define IDS_MIDI_ASS_COL_TARGET 268 +#define IDS_MIDI_EVT_COL_CHANNEL 269 +#define IDS_MIDI_EVT_COL_DEVICE 270 +#define IDS_MIDI_EVT_COL_MESSAGE 271 +#define IDS_MIDI_EVT_COL_P1 272 +#define IDS_MIDI_EVT_COL_P2 273 +#define IDS_MIDI_EVT_COL_PORT 274 +#define IDS_MIDI_EVT_COL_TIMESTAMP 275 +#define IDS_MIDI_EVT_PAUSE 276 +#define IDS_MIDI_FILE_FILTER 277 +#define IDS_MIDI_INPUT_BAR 278 +#define IDS_MIDI_NMAP_COL_ENABLE 279 +#define IDS_MIDI_NMAP_COL_FUNCTION 280 +#define IDS_MIDI_NMAP_COL_IN_CHAN 281 +#define IDS_MIDI_NMAP_COL_IN_DEVICE 282 +#define IDS_MIDI_NMAP_COL_IN_PORT 283 +#define IDS_MIDI_NMAP_COL_OUT_CHAN 284 +#define IDS_MIDI_NMAP_COL_OUT_DEVICE 285 +#define IDS_MIDI_NMAP_COL_OUT_PORT 286 +#define IDS_MIDI_NMAP_COL_PART_INDEX 287 +#define IDS_MIDI_NMAP_COL_PART_NAME 288 +#define IDS_MIDI_NMAP_COL_ZONE_HIGH 289 +#define IDS_MIDI_NMAP_COL_ZONE_LOW 290 +#define IDS_MIDI_OUTPUT_BAR 291 +#define IDS_MIDI_RECORDING_FILTER 292 +#define IDS_MIDI_REC_BAD_FORMAT 293 +#define IDS_MIDI_REC_OUT_OF_ORDER 294 +#define IDS_MIDI_STAT_ACTIVE_SENSING 295 +#define IDS_MIDI_STAT_CHANNEL_WILDCARD 296 +#define IDS_MIDI_STAT_CHAN_AFT 297 +#define IDS_MIDI_STAT_CLOCK 298 +#define IDS_MIDI_STAT_CONTINUE 299 +#define IDS_MIDI_STAT_CONTROL 300 +#define IDS_MIDI_STAT_EOX 301 +#define IDS_MIDI_STAT_KEY_AFT 302 +#define IDS_MIDI_STAT_MTC_QTR_FRAME 303 +#define IDS_MIDI_STAT_NOTE_OFF 304 +#define IDS_MIDI_STAT_NOTE_ON 305 +#define IDS_MIDI_STAT_PATCH 306 +#define IDS_MIDI_STAT_SONG_POSITION 307 +#define IDS_MIDI_STAT_SONG_SELECT 308 +#define IDS_MIDI_STAT_START 309 +#define IDS_MIDI_STAT_STOP 310 +#define IDS_MIDI_STAT_SYSEX 311 +#define IDS_MIDI_STAT_SYSTEM_RESET 312 +#define IDS_MIDI_STAT_SYSTEM_WILDCARD 313 +#define IDS_MIDI_STAT_TUNE_REQUEST 314 +#define IDS_MIDI_STAT_WHEEL 315 +#define IDS_MIDI_TARG_COL_CHAN 316 +#define IDS_MIDI_TARG_COL_CONTROL 317 +#define IDS_MIDI_TARG_COL_EVENT 318 +#define IDS_MIDI_TARG_COL_NAME 319 +#define IDS_MIDI_TARG_COL_PORT 320 +#define IDS_MIDI_TARG_COL_RANGE_END 321 +#define IDS_MIDI_TARG_COL_RANGE_START 322 +#define IDS_MIDI_TARG_COL_VALUE 323 +#define IDS_MSGBOX_NO 324 +#define IDS_MSGBOX_YES 325 +#define IDS_MTEVT_CHAN_AFTERTOUCH 326 +#define IDS_MTEVT_CONTROL 327 +#define IDS_MTEVT_NONE 328 +#define IDS_MTEVT_PROGRAM_CHANGE 329 +#define IDS_MTEVT_WHEEL 330 +#define IDS_NOT_APPLICABLE 331 +#define IDS_OPTIONS 332 +#define IDS_OPT_OTHER_DATA_FOLDER 333 +#define IDS_OPT_REC_OUTPUT_FOLDER 334 +#define IDS_OPT_RESET_ALL 335 +#define IDS_OPT_RESTORE_DEFAULTS 336 +#define IDS_OUTPUT_NOTES_BAR 337 +#define IDS_OUT_NOTES_FILTER_ALL 338 +#define IDS_OUT_NOTES_SM_ALL_CHANS 339 +#define IDS_OUT_NOTES_SM_ALL_PORTS 340 +#define IDS_OUT_NOTES_SM_FILTER_CHAN 341 +#define IDS_OUT_NOTES_SM_FILTER_PORT 342 +#define IDS_OUT_NOTES_SM_PIANO_SIZE 343 +#define IDS_PARTS_BAR 344 +#define IDS_PARTS_COL_FUNCTION 345 +#define IDS_PARTS_COL_PART_NAME 346 +#define IDS_PARTS_TIP_LIST 347 +#define IDS_PART_FORMAT 348 +#define IDS_PART_MT_AUTO_PLAY 349 +#define IDS_PART_MT_AUTO_VELOCITY 350 +#define IDS_PART_MT_AUTO_WINDOW 351 +#define IDS_PART_MT_BASS_APPROACH_LENGTH 352 +#define IDS_PART_MT_BASS_APPROACH_TRIGGER 353 +#define IDS_PART_MT_BASS_SLASH_CHORDS 354 +#define IDS_PART_MT_BASS_TARGET_ALIGNMENT 355 +#define IDS_PART_MT_COMP_ARP_ORDER 356 +#define IDS_PART_MT_COMP_ARP_PERIOD 357 +#define IDS_PART_MT_COMP_ARP_PERIOD_QUANT 358 +#define IDS_PART_MT_COMP_ARP_REPEAT 359 +#define IDS_PART_MT_COMP_VARIATION 360 +#define IDS_PART_MT_COMP_VOICING 361 +#define IDS_PART_MT_ENABLE 362 +#define IDS_PART_MT_FUNCTION 363 +#define IDS_PART_MT_IN_CC_NOTE 364 +#define IDS_PART_MT_IN_CC_NOTE_VEL 365 +#define IDS_PART_MT_IN_NON_DIATONIC 366 +#define IDS_PART_MT_IN_TRANSPOSE 367 +#define IDS_PART_MT_IN_VEL_OFFSET 368 +#define IDS_PART_MT_IN_ZONE_HIGH 369 +#define IDS_PART_MT_IN_ZONE_LOW 370 +#define IDS_PART_MT_LEAD_HARM_INTERVAL 371 +#define IDS_PART_MT_LEAD_HARM_OMIT_MELODY 372 +#define IDS_PART_MT_LEAD_HARM_STATIC_MAX 373 +#define IDS_PART_MT_LEAD_HARM_STATIC_MIN 374 +#define IDS_PART_MT_OUT_ANTICIPATION 375 +#define IDS_PART_MT_OUT_FIX_HELD_NOTES 376 +#define IDS_PART_MT_OUT_PATCH 377 +#define IDS_PART_MT_OUT_VOLUME 378 +#define IDS_PATCH_BAD_FORMAT 379 +#define IDS_PATCH_BAR 380 +#define IDS_PATCH_MT_LEAD_IN 381 +#define IDS_PATCH_MT_METRO_ENABLE 382 +#define IDS_PATCH_MT_METRO_VOLUME 383 +#define IDS_PATCH_MT_NEXT_CHORD 384 +#define IDS_PATCH_MT_NEXT_SECTION 385 +#define IDS_PATCH_MT_PAUSE 386 +#define IDS_PATCH_MT_PLAY 387 +#define IDS_PATCH_MT_PREV_CHORD 388 +#define IDS_PATCH_MT_REPEAT 389 +#define IDS_PATCH_MT_REWIND 390 +#define IDS_PATCH_MT_SONG_POSITION 391 +#define IDS_PATCH_MT_TEMPO 392 +#define IDS_PATCH_MT_TEMPO_MULTIPLE 393 +#define IDS_PATCH_MT_TRANSPOSE 394 +#define IDS_RECORD_AS 395 +#define IDS_RECORD_LOCKED 396 +#define IDS_REC_PLAY_COL_CHANNEL 397 +#define IDS_REC_PLAY_COL_DEVICE 398 +#define IDS_REC_PLAY_COL_EVENTS 399 +#define IDS_REC_PLAY_COL_NAME 400 +#define IDS_REC_PLAY_COL_PORT 401 +#define IDS_REC_PLAY_STOP_PLAYING 402 +#define IDS_REC_PLAY_STOP_RECORDING 403 +#define IDS_SECTION_NAME_SPACES 404 +#define IDS_SEC_LIST_COL_IMPLICIT 405 +#define IDS_SEC_LIST_COL_INDEX 406 +#define IDS_SEC_LIST_COL_LENGTH 407 +#define IDS_SEC_LIST_COL_NAME 408 +#define IDS_SEC_LIST_COL_REPEAT 409 +#define IDS_SEC_LIST_COL_START 410 +#define IDS_SONG_ERR_BAD_BASS_NOTE 411 +#define IDS_SONG_ERR_BAD_CHORD 412 +#define IDS_SONG_ERR_BAD_CHORD_TYPE 413 +#define IDS_SONG_ERR_BAD_COMMAND 414 +#define IDS_SONG_ERR_BAD_DURATION 415 +#define IDS_SONG_ERR_BAD_KEY 416 +#define IDS_SONG_ERR_BAD_METER 417 +#define IDS_SONG_ERR_BAD_MODE 418 +#define IDS_SONG_ERR_BAD_ROOT 419 +#define IDS_SONG_ERR_BAD_SCALE 420 +#define IDS_SONG_ERR_BAD_SYNTAX 421 +#define IDS_SONG_ERR_BAD_TEMPO 422 +#define IDS_SONG_ERR_CHORD_TONE_RANGE 423 +#define IDS_SONG_ERR_DUP_CHORD_TYPE 424 +#define IDS_SONG_ERR_READ 425 +#define IDS_SONG_ERR_SEC_BAD_REPEAT 426 +#define IDS_SONG_ERR_SEC_BAD_SYNTAX 427 +#define IDS_SONG_ERR_SEC_CANT_NEST 428 +#define IDS_SONG_ERR_SEC_UNTERMINATED 429 +#define IDS_THREADS_COL_KERNEL_TIME 430 +#define IDS_THREADS_COL_PRIORITY 431 +#define IDS_THREADS_COL_THREAD_ID 432 +#define IDS_THREADS_COL_USER_TIME 433 +#define IDS_UC_BASE_PATCH 434 +#define IDS_UC_CUT 435 +#define IDS_UC_DELETE 436 +#define IDS_UC_ENABLE_PART 437 +#define IDS_UC_INSERT 438 +#define IDS_UC_MIDI_CHASE 439 +#define IDS_UC_MIDI_TARGETS 440 +#define IDS_UC_PART 441 +#define IDS_UC_PASTE 442 +#define IDS_UC_RENAME 443 +#define IDS_UC_REORDER 444 +#define IDS_UC_SELECT_PART 445 +#define IDS_UC_SELECT_PART_PAGE 446 +#define IDS_UC_SELECT_PATCH_PAGE 447 #define IDC_ABOUT_LICENSE 1001 #define IDC_ABOUT_TEXT 1002 #define IDC_ABOUT_URL 1003 @@ -315,124 +317,125 @@ #define IDC_MIDI_ASSIGNS_LIST 1021 #define IDC_MIDI_EVENT_LIST 1022 #define IDC_MIDI_NOTE_MAP_LIST 1023 -#define IDC_MIDI_TARGET 1024 -#define IDC_MIDI_TARG_COL_CHAN 1025 -#define IDC_MIDI_TARG_COL_CONTROL 1026 -#define IDC_MIDI_TARG_COL_EVENT 1027 -#define IDC_MIDI_TARG_COL_NAME 1028 -#define IDC_MIDI_TARG_COL_PORT 1029 -#define IDC_MIDI_TARG_COL_RANGE_END 1030 -#define IDC_MIDI_TARG_COL_RANGE_START 1031 -#define IDC_MSGBOXCHK_CHECK 1032 -#define IDC_MSGBOXCHK_TEXT 1033 -#define IDC_NOTEPAD_EDIT 1034 -#define IDC_OPT_CHART_CHOOSE_FONT 1035 -#define IDC_OPT_CHART_DEFAULT_FONT 1036 -#define IDC_OPT_CHART_LINE_MEASURES 1037 -#define IDC_OPT_OTHER_AUTO_CHECK_UPDATES 1038 -#define IDC_OPT_OTHER_DATA_FOLDER_BROWSE 1039 -#define IDC_OPT_OTHER_DATA_FOLDER_PATH 1040 -#define IDC_OPT_OTHER_DATA_FOLDER_TYPE 1041 -#define IDC_OPT_OTHER_DATA_FOLDER_TYPE2 1042 -#define IDC_OPT_OTHER_SHOW_TOOLTIPS 1043 -#define IDC_OPT_REC_ALWAYS_RECORD 1044 -#define IDC_OPT_REC_BUFFER_SIZE 1045 -#define IDC_OPT_REC_FOLDER_BROWSE 1046 -#define IDC_OPT_REC_FOLDER_PATH 1047 -#define IDC_OPT_REC_FOLDER_TYPE 1048 -#define IDC_OPT_REC_FOLDER_TYPE2 1049 -#define IDC_OPT_REC_MIDI_FILE_PPQ 1050 -#define IDC_OPT_REC_PROMPT_FILENAME 1051 -#define IDC_PARTS_LIST 1052 -#define IDC_PART_AUTO_PLAY 1053 -#define IDC_PART_AUTO_VELOCITY 1054 -#define IDC_PART_AUTO_WINDOW 1055 -#define IDC_PART_BASS_APPROACH_LENGTH 1056 -#define IDC_PART_BASS_APPROACH_TRIGGER 1057 -#define IDC_PART_BASS_LOWEST 1058 -#define IDC_PART_BASS_SLASH_CHORDS 1059 -#define IDC_PART_BASS_TARGET_ALIGNMENT 1060 -#define IDC_PART_COMP_ARP_ORDER 1061 -#define IDC_PART_COMP_ARP_PERIOD 1062 -#define IDC_PART_COMP_ARP_PERIOD_QUANT 1063 -#define IDC_PART_COMP_ARP_REPEAT 1064 -#define IDC_PART_COMP_CHORD_RESETS_ALT 1065 -#define IDC_PART_COMP_VARIATION 1066 -#define IDC_PART_COMP_VOICING 1067 -#define IDC_PART_ENABLE 1068 -#define IDC_PART_FUNCTION 1069 -#define IDC_PART_IN_CC_NOTE 1070 -#define IDC_PART_IN_CC_NOTE_VEL 1071 -#define IDC_PART_IN_CHAN 1072 -#define IDC_PART_IN_DEVICE_NAME 1073 -#define IDC_PART_IN_NON_DIATONIC 1074 -#define IDC_PART_IN_PORT 1075 -#define IDC_PART_IN_TRANSPOSE 1076 -#define IDC_PART_IN_VEL_OFFSET 1077 -#define IDC_PART_IN_ZONE_HIGH 1078 -#define IDC_PART_IN_ZONE_LOW 1079 -#define IDC_PART_LEAD_HARM_INTERVAL 1080 -#define IDC_PART_LEAD_HARM_OMIT_MELODY 1081 -#define IDC_PART_LEAD_HARM_STATIC_MAX 1082 -#define IDC_PART_LEAD_HARM_STATIC_MIN 1083 -#define IDC_PART_MIDI_ROW 1084 -#define IDC_PART_NAME 1085 -#define IDC_PART_OUT_ANTICIPATION 1086 -#define IDC_PART_OUT_CHAN 1087 -#define IDC_PART_OUT_CONTROLS_THRU 1088 -#define IDC_PART_OUT_DEVICE_NAME 1089 -#define IDC_PART_OUT_FIX_HELD_NOTES 1090 -#define IDC_PART_OUT_LOCAL_CONTROL 1091 -#define IDC_PART_OUT_PATCH 1092 -#define IDC_PART_OUT_PORT 1093 -#define IDC_PART_OUT_VOLUME 1094 -#define IDC_PATCH_AINST_CHANNEL 1095 -#define IDC_PATCH_AINST_ENABLE 1096 -#define IDC_PATCH_AINST_PATCH 1097 -#define IDC_PATCH_AINST_PORT 1098 -#define IDC_PATCH_AINST_VELOCITY 1099 -#define IDC_PATCH_AINST_VOLUME 1100 -#define IDC_PATCH_GEN_KEY 1101 -#define IDC_PATCH_GEN_LEAD_IN 1102 -#define IDC_PATCH_GEN_PPQ 1103 -#define IDC_PATCH_GEN_TEMPO 1104 -#define IDC_PATCH_GEN_TEMPO_MULTIPLE 1105 -#define IDC_PATCH_GEN_TRANSPOSE 1106 -#define IDC_PATCH_METRO_ACCENT_NOTE 1107 -#define IDC_PATCH_METRO_ACCENT_SAME_NOTE 1108 -#define IDC_PATCH_METRO_ACCENT_VEL 1109 -#define IDC_PATCH_METRO_NOTE 1110 -#define IDC_PIANO_CHANNEL 1111 -#define IDC_PIANO_KEY_COUNT 1112 -#define IDC_PIANO_PORT 1113 -#define IDC_PIANO_START_NOTE 1114 -#define IDC_PIANO_VELOCITY 1115 -#define IDC_PROGRESS 1116 -#define IDC_PROGRESS_PERCENT 1117 -#define IDC_REC_PLAY_DURATION 1118 -#define IDC_REC_PLAY_EXPORT 1119 -#define IDC_REC_PLAY_OPEN 1120 -#define IDC_REC_PLAY_PLAY 1121 -#define IDC_REC_PLAY_POSITION 1122 -#define IDC_REC_PLAY_POS_SLIDER 1123 -#define IDC_REC_PLAY_SAVE 1124 -#define IDC_REC_PLAY_STOP 1125 -#define IDC_REC_PLAY_TITLE 1126 -#define IDC_REC_PLAY_TRACK_LIST 1127 -#define IDC_SECTION_LIST 1128 -#define IDC_SECTION_PROPS_LENGTH 1129 -#define IDC_SECTION_PROPS_NAME 1130 -#define IDC_SECTION_PROPS_REPEAT 1131 -#define IDC_SECTION_PROPS_START 1132 -#define IDC_SONG_PROPS_COMMENTS 1133 -#define IDC_SONG_PROPS_KEY_SIG 1134 -#define IDC_SONG_PROPS_TEMPO 1135 -#define IDC_SONG_PROPS_TIME_SIG_DENOM 1136 -#define IDC_SONG_PROPS_TIME_SIG_NUMER 1137 -#define IDC_SONG_PROPS_TRANSPOSE 1138 -#define IDC_SPLASH_ICON 1139 -#define IDC_TABDLG_TAB 1140 -#define IDC_THREADS_LIST 1141 +#define IDC_MIDI_TARGET_LIST 1024 +#define IDC_MIDI_TARG_CHAN 1025 +#define IDC_MIDI_TARG_CONTROL 1026 +#define IDC_MIDI_TARG_EVENT 1027 +#define IDC_MIDI_TARG_NAME 1028 +#define IDC_MIDI_TARG_PORT 1029 +#define IDC_MIDI_TARG_RANGE_END 1030 +#define IDC_MIDI_TARG_RANGE_START 1031 +#define IDC_MIDI_TARG_VALUE 1032 +#define IDC_MSGBOXCHK_CHECK 1033 +#define IDC_MSGBOXCHK_TEXT 1034 +#define IDC_NOTEPAD_EDIT 1035 +#define IDC_OPT_CHART_CHOOSE_FONT 1036 +#define IDC_OPT_CHART_DEFAULT_FONT 1037 +#define IDC_OPT_CHART_LINE_MEASURES 1038 +#define IDC_OPT_OTHER_AUTO_CHECK_UPDATES 1039 +#define IDC_OPT_OTHER_DATA_FOLDER_BROWSE 1040 +#define IDC_OPT_OTHER_DATA_FOLDER_PATH 1041 +#define IDC_OPT_OTHER_DATA_FOLDER_TYPE 1042 +#define IDC_OPT_OTHER_DATA_FOLDER_TYPE2 1043 +#define IDC_OPT_OTHER_SHOW_TOOLTIPS 1044 +#define IDC_OPT_REC_ALWAYS_RECORD 1045 +#define IDC_OPT_REC_BUFFER_SIZE 1046 +#define IDC_OPT_REC_FOLDER_BROWSE 1047 +#define IDC_OPT_REC_FOLDER_PATH 1048 +#define IDC_OPT_REC_FOLDER_TYPE 1049 +#define IDC_OPT_REC_FOLDER_TYPE2 1050 +#define IDC_OPT_REC_MIDI_FILE_PPQ 1051 +#define IDC_OPT_REC_PROMPT_FILENAME 1052 +#define IDC_PARTS_LIST 1053 +#define IDC_PART_AUTO_PLAY 1054 +#define IDC_PART_AUTO_VELOCITY 1055 +#define IDC_PART_AUTO_WINDOW 1056 +#define IDC_PART_BASS_APPROACH_LENGTH 1057 +#define IDC_PART_BASS_APPROACH_TRIGGER 1058 +#define IDC_PART_BASS_LOWEST 1059 +#define IDC_PART_BASS_SLASH_CHORDS 1060 +#define IDC_PART_BASS_TARGET_ALIGNMENT 1061 +#define IDC_PART_COMP_ARP_ORDER 1062 +#define IDC_PART_COMP_ARP_PERIOD 1063 +#define IDC_PART_COMP_ARP_PERIOD_QUANT 1064 +#define IDC_PART_COMP_ARP_REPEAT 1065 +#define IDC_PART_COMP_CHORD_RESETS_ALT 1066 +#define IDC_PART_COMP_VARIATION 1067 +#define IDC_PART_COMP_VOICING 1068 +#define IDC_PART_ENABLE 1069 +#define IDC_PART_FUNCTION 1070 +#define IDC_PART_IN_CC_NOTE 1071 +#define IDC_PART_IN_CC_NOTE_VEL 1072 +#define IDC_PART_IN_CHAN 1073 +#define IDC_PART_IN_DEVICE_NAME 1074 +#define IDC_PART_IN_NON_DIATONIC 1075 +#define IDC_PART_IN_PORT 1076 +#define IDC_PART_IN_TRANSPOSE 1077 +#define IDC_PART_IN_VEL_OFFSET 1078 +#define IDC_PART_IN_ZONE_HIGH 1079 +#define IDC_PART_IN_ZONE_LOW 1080 +#define IDC_PART_LEAD_HARM_INTERVAL 1081 +#define IDC_PART_LEAD_HARM_OMIT_MELODY 1082 +#define IDC_PART_LEAD_HARM_STATIC_MAX 1083 +#define IDC_PART_LEAD_HARM_STATIC_MIN 1084 +#define IDC_PART_MIDI_ROW 1085 +#define IDC_PART_NAME 1086 +#define IDC_PART_OUT_ANTICIPATION 1087 +#define IDC_PART_OUT_CHAN 1088 +#define IDC_PART_OUT_CONTROLS_THRU 1089 +#define IDC_PART_OUT_DEVICE_NAME 1090 +#define IDC_PART_OUT_FIX_HELD_NOTES 1091 +#define IDC_PART_OUT_LOCAL_CONTROL 1092 +#define IDC_PART_OUT_PATCH 1093 +#define IDC_PART_OUT_PORT 1094 +#define IDC_PART_OUT_VOLUME 1095 +#define IDC_PATCH_GEN_KEY 1096 +#define IDC_PATCH_GEN_LEAD_IN 1097 +#define IDC_PATCH_GEN_PPQ 1098 +#define IDC_PATCH_GEN_TEMPO 1099 +#define IDC_PATCH_GEN_TEMPO_MULTIPLE 1100 +#define IDC_PATCH_GEN_TRANSPOSE 1101 +#define IDC_PATCH_METRO_ACCENT_NOTE 1102 +#define IDC_PATCH_METRO_ACCENT_SAME_NOTE 1103 +#define IDC_PATCH_METRO_ACCENT_VEL 1104 +#define IDC_PATCH_METRO_CHANNEL 1105 +#define IDC_PATCH_METRO_ENABLE 1106 +#define IDC_PATCH_METRO_NOTE 1107 +#define IDC_PATCH_METRO_PATCH 1108 +#define IDC_PATCH_METRO_PORT 1109 +#define IDC_PATCH_METRO_VELOCITY 1110 +#define IDC_PATCH_METRO_VOLUME 1111 +#define IDC_PIANO_CHANNEL 1112 +#define IDC_PIANO_KEY_COUNT 1113 +#define IDC_PIANO_PORT 1114 +#define IDC_PIANO_START_NOTE 1115 +#define IDC_PIANO_VELOCITY 1116 +#define IDC_PROGRESS 1117 +#define IDC_PROGRESS_PERCENT 1118 +#define IDC_REC_PLAY_DURATION 1119 +#define IDC_REC_PLAY_EXPORT 1120 +#define IDC_REC_PLAY_OPEN 1121 +#define IDC_REC_PLAY_PLAY 1122 +#define IDC_REC_PLAY_POSITION 1123 +#define IDC_REC_PLAY_POS_SLIDER 1124 +#define IDC_REC_PLAY_SAVE 1125 +#define IDC_REC_PLAY_STOP 1126 +#define IDC_REC_PLAY_TITLE 1127 +#define IDC_REC_PLAY_TRACK_LIST 1128 +#define IDC_SECTION_LIST 1129 +#define IDC_SECTION_PROPS_LENGTH 1130 +#define IDC_SECTION_PROPS_NAME 1131 +#define IDC_SECTION_PROPS_REPEAT 1132 +#define IDC_SECTION_PROPS_START 1133 +#define IDC_SONG_PROPS_COMMENTS 1134 +#define IDC_SONG_PROPS_KEY_SIG 1135 +#define IDC_SONG_PROPS_TEMPO 1136 +#define IDC_SONG_PROPS_TIME_SIG_DENOM 1137 +#define IDC_SONG_PROPS_TIME_SIG_NUMER 1138 +#define IDC_SONG_PROPS_TRANSPOSE 1139 +#define IDC_SPLASH_ICON 1140 +#define IDC_TABDLG_TAB 1141 +#define IDC_THREADS_LIST 1142 #define ID_APP_CHECK_FOR_UPDATES 32771 #define ID_APP_DEMO 32772 #define ID_APP_HOME_PAGE 32773 @@ -464,50 +467,51 @@ #define ID_MIDI_OUTPUT 32799 #define ID_MIDI_PANIC 32800 #define ID_MIDI_RESET_ALL 32801 -#define ID_OUT_NOTES_ROTATE_LABELS 32802 -#define ID_OUT_NOTES_SHOW_KEY_LABELS 32803 -#define ID_OUT_NOTES_SHOW_METRONOME 32804 -#define ID_PATCH_MRU_FILE1 32805 -#define ID_PATCH_MRU_FILE2 32806 -#define ID_PATCH_MRU_FILE3 32807 -#define ID_PATCH_MRU_FILE4 32808 -#define ID_PATCH_NEW 32809 -#define ID_PATCH_OPEN 32810 -#define ID_PATCH_SAVE 32811 -#define ID_PATCH_SAVE_AS 32812 -#define ID_PIANO_KEY_LABEL_TYPE 32813 -#define ID_PIANO_KEY_LABEL_TYPE2 32814 -#define ID_PIANO_KEY_LABEL_TYPE3 32815 -#define ID_PIANO_KEY_LABEL_TYPE4 32816 -#define ID_PIANO_KEY_LABEL_TYPE5 32817 -#define ID_PIANO_KEY_LABEL_TYPE6 32818 -#define ID_PIANO_ROTATE_LABELS 32819 -#define ID_PIANO_SHOW_OCTAVES 32820 -#define ID_PIANO_VERTICAL 32821 -#define ID_TRANSPORT_AUTO_REWIND 32822 -#define ID_TRANSPORT_NEXT_CHORD 32823 -#define ID_TRANSPORT_NEXT_SECTION 32824 -#define ID_TRANSPORT_PAUSE 32825 -#define ID_TRANSPORT_PLAY 32826 -#define ID_TRANSPORT_PREV_CHORD 32827 -#define ID_TRANSPORT_RECORD 32828 -#define ID_TRANSPORT_REPEAT 32829 -#define ID_TRANSPORT_REWIND 32830 -#define ID_VIEW_OUTPUT_NOTES 32831 -#define ID_VIEW_PARTS 32832 -#define ID_VIEW_PATCH 32833 -#define ID_VIEW_PIANO 32834 -#define ID_VIEW_RECORD_PLAYER 32835 -#define ID_VIEW_THREADS 32836 +#define ID_MIDI_TARGET_RESET 32802 +#define ID_OUT_NOTES_ROTATE_LABELS 32803 +#define ID_OUT_NOTES_SHOW_KEY_LABELS 32804 +#define ID_OUT_NOTES_SHOW_METRONOME 32805 +#define ID_PATCH_MRU_FILE1 32806 +#define ID_PATCH_MRU_FILE2 32807 +#define ID_PATCH_MRU_FILE3 32808 +#define ID_PATCH_MRU_FILE4 32809 +#define ID_PATCH_NEW 32810 +#define ID_PATCH_OPEN 32811 +#define ID_PATCH_SAVE 32812 +#define ID_PATCH_SAVE_AS 32813 +#define ID_PIANO_KEY_LABEL_TYPE 32814 +#define ID_PIANO_KEY_LABEL_TYPE2 32815 +#define ID_PIANO_KEY_LABEL_TYPE3 32816 +#define ID_PIANO_KEY_LABEL_TYPE4 32817 +#define ID_PIANO_KEY_LABEL_TYPE5 32818 +#define ID_PIANO_KEY_LABEL_TYPE6 32819 +#define ID_PIANO_ROTATE_LABELS 32820 +#define ID_PIANO_SHOW_OCTAVES 32821 +#define ID_PIANO_VERTICAL 32822 +#define ID_TRANSPORT_AUTO_REWIND 32823 +#define ID_TRANSPORT_NEXT_CHORD 32824 +#define ID_TRANSPORT_NEXT_SECTION 32825 +#define ID_TRANSPORT_PAUSE 32826 +#define ID_TRANSPORT_PLAY 32827 +#define ID_TRANSPORT_PREV_CHORD 32828 +#define ID_TRANSPORT_RECORD 32829 +#define ID_TRANSPORT_REPEAT 32830 +#define ID_TRANSPORT_REWIND 32831 +#define ID_VIEW_OUTPUT_NOTES 32832 +#define ID_VIEW_PARTS 32833 +#define ID_VIEW_PATCH 32834 +#define ID_VIEW_PIANO 32835 +#define ID_VIEW_RECORD_PLAYER 32836 +#define ID_VIEW_THREADS 32837 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 445 -#define _APS_NEXT_COMMAND_VALUE 32837 -#define _APS_NEXT_CONTROL_VALUE 1142 +#define _APS_NEXT_RESOURCE_VALUE 448 +#define _APS_NEXT_COMMAND_VALUE 32838 +#define _APS_NEXT_CONTROL_VALUE 1143 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif