diff --git a/src/grandorgue/CMakeLists.txt b/src/grandorgue/CMakeLists.txt index 1129dbfcd..537a54d3c 100644 --- a/src/grandorgue/CMakeLists.txt +++ b/src/grandorgue/CMakeLists.txt @@ -142,6 +142,7 @@ loader/cache/GOCacheCleaner.cpp loader/cache/GOCacheWriter.cpp midi/dialog-creator/GOMidiDialogCreatorProxy.cpp midi/objects/GOMidiObject.cpp +midi/objects/GOMidiObjectContext.cpp midi/objects/GOMidiObjectWithDivision.cpp midi/objects/GOMidiObjectWithShortcut.cpp midi/objects/GOMidiReceivingSendingObject.cpp diff --git a/src/grandorgue/control/GOElementCreator.cpp b/src/grandorgue/control/GOElementCreator.cpp index e90d64d32..880e00c67 100644 --- a/src/grandorgue/control/GOElementCreator.cpp +++ b/src/grandorgue/control/GOElementCreator.cpp @@ -1,6 +1,6 @@ /* * Copyright 2006 Milan Digital Audio LLC - * Copyright 2009-2023 GrandOrgue contributors (see AUTHORS) + * Copyright 2009-2025 GrandOrgue contributors (see AUTHORS) * License GPL-2.0 or later * (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). */ @@ -10,14 +10,17 @@ #include "GOCallbackButtonControl.h" void GOElementCreator::CreateButtons(GOOrganModel &organModel) { - const struct ButtonDefinitionEntry *entries = GetButtonDefinitionList(); - for (unsigned i = 0; - entries[i].name != wxEmptyString && entries[i].value >= 0; - i++) { - if (m_buttons.size() <= (unsigned)entries[i].value) - m_buttons.resize(entries[i].value + 1); - m_buttons[entries[i].value] = new GOCallbackButtonControl( - organModel, this, entries[i].is_pushbutton, entries[i].is_piston); + for (const ButtonDefinitionEntry *pEntry = GetButtonDefinitionList(); + !pEntry->name.IsEmpty() && pEntry->value >= 0; + pEntry++) { + GOCallbackButtonControl *pButton = new GOCallbackButtonControl( + organModel, this, pEntry->is_pushbutton, pEntry->is_piston); + const unsigned buttonIndex = (unsigned)pEntry->value; + + pButton->SetContext(pEntry->p_MidiContext); + if (m_buttons.size() <= buttonIndex) + m_buttons.resize(buttonIndex + 1); + m_buttons[buttonIndex] = pButton; } } diff --git a/src/grandorgue/control/GOElementCreator.h b/src/grandorgue/control/GOElementCreator.h index f52ca14f0..08dda4a11 100644 --- a/src/grandorgue/control/GOElementCreator.h +++ b/src/grandorgue/control/GOElementCreator.h @@ -1,6 +1,6 @@ /* * Copyright 2006 Milan Digital Audio LLC - * Copyright 2009-2023 GrandOrgue contributors (see AUTHORS) + * Copyright 2009-2025 GrandOrgue contributors (see AUTHORS) * License GPL-2.0 or later * (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). */ @@ -15,9 +15,10 @@ class GOButtonControl; class GOConfigReader; -class GOOrganModel; class GOEnclosure; class GOLabelControl; +class GOMidiObjectContext; +class GOOrganModel; class GOElementCreator : private GOButtonCallback { public: @@ -27,6 +28,7 @@ class GOElementCreator : private GOButtonCallback { bool is_public; bool is_pushbutton; bool is_piston; + const GOMidiObjectContext *p_MidiContext = nullptr; }; protected: diff --git a/src/grandorgue/control/GOLabelControl.cpp b/src/grandorgue/control/GOLabelControl.cpp index ab963d266..35cd37bfc 100644 --- a/src/grandorgue/control/GOLabelControl.cpp +++ b/src/grandorgue/control/GOLabelControl.cpp @@ -14,13 +14,14 @@ const wxString WX_MIDI_TYPE_CODE = wxT("Label"); const wxString WX_MIDI_TYPE_NAME = _("Label"); -GOLabelControl::GOLabelControl(GOOrganModel &organModel) +GOLabelControl::GOLabelControl( + GOOrganModel &organModel, const GOMidiObjectContext *pContext) : GOMidiSendingObject( - organModel, WX_MIDI_TYPE_CODE, WX_MIDI_TYPE_NAME, MIDI_SEND_LABEL) {} - -const wxString &GOLabelControl::GetContent() { return m_Content; } + organModel, WX_MIDI_TYPE_CODE, WX_MIDI_TYPE_NAME, MIDI_SEND_LABEL) { + SetContext(pContext); +} -void GOLabelControl::SetContent(wxString name) { +void GOLabelControl::SetContent(const wxString &name) { m_Content = name; SendMidiValue(m_Content); r_OrganModel.SendControlChanged(this); @@ -36,8 +37,6 @@ void GOLabelControl::PrepareRecording() { SendMidiValue(m_Content); } -wxString GOLabelControl::GetElementStatus() { return m_Content; } - std::vector GOLabelControl::GetElementActions() { std::vector actions; return actions; diff --git a/src/grandorgue/control/GOLabelControl.h b/src/grandorgue/control/GOLabelControl.h index 206d838b6..c51f3d7da 100644 --- a/src/grandorgue/control/GOLabelControl.h +++ b/src/grandorgue/control/GOLabelControl.h @@ -19,6 +19,7 @@ class GOConfigReader; class GOConfigWriter; +class GOMidiObjectContext; class GOOrganModel; class GOLabelControl : public GOControl, public GOMidiSendingObject { @@ -29,11 +30,12 @@ class GOLabelControl : public GOControl, public GOMidiSendingObject { void PrepareRecording() override; public: - GOLabelControl(GOOrganModel &organModel); - const wxString &GetContent(); - void SetContent(wxString name); + GOLabelControl( + GOOrganModel &organModel, const GOMidiObjectContext *pContext = nullptr); + const wxString &GetContent() const { return m_Content; } + void SetContent(const wxString &name); - wxString GetElementStatus() override; + wxString GetElementStatus() override { return m_Content; } std::vector GetElementActions() override; void TriggerElementActions(unsigned no) override; }; diff --git a/src/grandorgue/midi/objects/GOMidiObject.cpp b/src/grandorgue/midi/objects/GOMidiObject.cpp index 0c70787d1..b2b2dca35 100644 --- a/src/grandorgue/midi/objects/GOMidiObject.cpp +++ b/src/grandorgue/midi/objects/GOMidiObject.cpp @@ -12,6 +12,8 @@ #include "midi/GOMidiReceiver.h" #include "model/GOOrganModel.h" +#include "GOMidiObjectContext.h" + GOMidiObject::GOMidiObject( GOOrganModel &organModel, const wxString &midiTypeCode, @@ -23,7 +25,8 @@ GOMidiObject::GOMidiObject( p_MidiSender(nullptr), p_MidiReceiver(nullptr), p_ShortcutReceiver(nullptr), - p_DivisionSender(nullptr) { + p_DivisionSender(nullptr), + p_context(nullptr) { r_OrganModel.RegisterSoundStateHandler(this); r_OrganModel.RegisterMidiObject(this); } @@ -34,6 +37,10 @@ GOMidiObject::~GOMidiObject() { r_OrganModel.UnRegisterSoundStateHandler(this); } +wxString GOMidiObject::GetContextTitle() const { + return GOMidiObjectContext::getFullTitle(p_context); +} + void GOMidiObject::InitMidiObject( GOConfigReader &cfg, const wxString &group, const wxString &name) { SetGroup(group); diff --git a/src/grandorgue/midi/objects/GOMidiObject.h b/src/grandorgue/midi/objects/GOMidiObject.h index 34616e1bc..7678cd711 100644 --- a/src/grandorgue/midi/objects/GOMidiObject.h +++ b/src/grandorgue/midi/objects/GOMidiObject.h @@ -17,6 +17,7 @@ #include "GOSaveableObject.h" class GOMidiMap; +class GOMidiObjectContext; class GOMidiReceiver; class GOMidiSender; class GOMidiShortcutReceiver; @@ -38,6 +39,8 @@ class GOMidiObject : public GOSoundStateHandler, public GOSaveableObject { GOMidiShortcutReceiver *p_ShortcutReceiver; GOMidiSender *p_DivisionSender; + const GOMidiObjectContext *p_context; + protected: GOMidiObject( GOOrganModel &organModel, @@ -80,6 +83,11 @@ class GOMidiObject : public GOSoundStateHandler, public GOSaveableObject { const wxString &GetName() const { return m_name; } void SetName(const wxString &name) { m_name = name; } + const GOMidiObjectContext *GetContext() const { return p_context; } + void SetContext(const GOMidiObjectContext *pContext) { p_context = pContext; } + + wxString GetContextTitle() const; + virtual void Init( GOConfigReader &cfg, const wxString &group, const wxString &name) { InitMidiObject(cfg, group, name); diff --git a/src/grandorgue/midi/objects/GOMidiObjectContext.cpp b/src/grandorgue/midi/objects/GOMidiObjectContext.cpp new file mode 100644 index 000000000..365155c34 --- /dev/null +++ b/src/grandorgue/midi/objects/GOMidiObjectContext.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2006 Milan Digital Audio LLC + * Copyright 2009-2025 GrandOrgue contributors (see AUTHORS) + * License GPL-2.0 or later + * (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). + */ + +#include "GOMidiObjectContext.h" + +const wxString WX_PATH_SEPARATOR = "/"; + +GOMidiObjectContext::GOMidiObjectContext( + const wxString &name, + const wxString &title, + const GOMidiObjectContext *pParent) + : m_name(name), m_title(title), p_parent(pParent) {} + +wxString GOMidiObjectContext::getFullTitle( + const GOMidiObjectContext *pContext) { + wxString path; + + for (; pContext; pContext = pContext->p_parent) { + if (!path.IsEmpty()) + path = WX_PATH_SEPARATOR + path; + path = pContext->m_title + path; + } + return path; +} diff --git a/src/grandorgue/midi/objects/GOMidiObjectContext.h b/src/grandorgue/midi/objects/GOMidiObjectContext.h new file mode 100644 index 000000000..d76b8c801 --- /dev/null +++ b/src/grandorgue/midi/objects/GOMidiObjectContext.h @@ -0,0 +1,46 @@ +/* + * Copyright 2006 Milan Digital Audio LLC + * Copyright 2009-2025 GrandOrgue contributors (see AUTHORS) + * License GPL-2.0 or later + * (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). + */ + +#ifndef GOMIDIOBJECTCONTEXT_H +#define GOMIDIOBJECTCONTEXT_H + +#include + +/** + * This class is used for describing a place where a midi object is used. + * There is a hierarhial tree of contexts. For example, setter, manuals/1/stops, + * manuals/1/divisionals + */ + +class GOMidiObjectContext { +private: + // Name. Not translated. Used for exports + wxString m_name; + + // Title. Translated. Used in UI + wxString m_title; + + // Parent context + const GOMidiObjectContext *p_parent; + +public: + GOMidiObjectContext( + const wxString &name, + const wxString &title, + const GOMidiObjectContext *pParent = nullptr); + GOMidiObjectContext() + : GOMidiObjectContext(wxEmptyString, wxEmptyString, nullptr) {} + + const wxString &GetName() const { return m_name; } + const wxString &GetTitle() const { return m_title; } + void SetTitle(const wxString title) { m_title = title; } + const GOMidiObjectContext *GetParent() const { return p_parent; } + + static wxString getFullTitle(const GOMidiObjectContext *pContext); +}; + +#endif /* GOMIDIOBJECTCONTEXT_H */