MIDI2LR 6.2.0.1
MIDI2LR is an application that interfaces MIDI controllers with Lightroom 6+/CC Classic. It processes MIDI input into develop parameter updates and photo actions, and sends MIDI output when parameters are changed for motorized feedback (on controllers that have motorized faders). A listing of available LightRoom commands is in the Wiki. Assistance on the code and design is welcome.
Loading...
Searching...
No Matches
MainContentComponent Class Referencefinal

#include <MainComponent.h>

+ Inheritance diagram for MainContentComponent:

Public Member Functions

 MainContentComponent (const CommandSet &command_set, Profile &profile, ProfileManager &profile_manager, SettingsManager &settings_manager, LrIpcOut &lr_ipc_out, MidiReceiver &midi_receiver, MidiSender &midi_sender)
 
 MainContentComponent (const MainContentComponent &other)=delete
 
 MainContentComponent (MainContentComponent &&other)=delete
 
 ~MainContentComponent ()
 
void Init ()
 
MainContentComponentoperator= (const MainContentComponent &other)=delete
 
MainContentComponentoperator= (MainContentComponent &&other)=delete
 
void SaveProfile () const
 

Private Member Functions

void AddComponent (juce::Component &component, int x, int y, int width, int height)
 
void DisconnectClicked ()
 
void handleAsyncUpdate () override
 
void LoadClicked ()
 
void LrIpcOutCallback (bool, bool)
 
void MidiCmdCallback (rsj::MidiMessage mm)
 
void paint (juce::Graphics &) override
 
void ProfileChanged (juce::XmlElement *xml_element, const juce::String &file_name)
 
void RemoveAllRowsClicked ()
 
void RemoveUnassignedClicked ()
 
void RescanClicked ()
 
void SettingsClicked ()
 
void timerCallback () override
 
void UpdateConnectionLabel (const char *text, juce::Colour colour)
 

Private Attributes

juce::Label command_label_ {"Command", ""}
 
CommandTable command_table_ {"Table", nullptr}
 
CommandTableModel command_table_model_
 
juce::Label connection_label_ {"Connection", juce::translate("Not connected to Lightroom")}
 
juce::TextButton disconnect_button_ {juce::translate("Halt sending to Lightroom")}
 
juce::String last_command_
 
juce::TextButton load_button_ {juce::translate("Load")}
 
LrIpcOutlr_ipc_out_
 
MidiReceivermidi_receiver_
 
MidiSendermidi_sender_
 
Profileprofile_
 
ProfileManagerprofile_manager_
 
juce::Label profile_name_label_ {"ProfileNameLabel", ""}
 
juce::TextButton remove_allrows_button_ {juce::translate("Clear ALL rows")}
 
juce::TextButton remove_unassigned_button_ {juce::translate("Remove unassigned rows")}
 
juce::TextButton rescan_button_ {juce::translate("Rescan MIDI devices")}
 
size_t row_to_select_ {0}
 
juce::TextButton save_button_ {juce::translate("Save")}
 
juce::TextButton settings_button_ {juce::translate("Settings")}
 
std::unique_ptr< juce::DialogWindow > settings_dialog_
 
SettingsManagersettings_manager_
 
juce::Label title_label_ {"Title", "MIDI2LR"}
 
juce::DropShadowEffect title_shadow_
 
juce::Label version_label_
 

Constructor & Destructor Documentation

◆ MainContentComponent() [1/3]

MainContentComponent::MainContentComponent ( const CommandSet command_set,
Profile profile,
ProfileManager profile_manager,
SettingsManager settings_manager,
LrIpcOut lr_ipc_out,
MidiReceiver midi_receiver,
MidiSender midi_sender 
)
66 : ResizableLayout{this}, command_table_model_(command_set, profile), lr_ipc_out_{lr_ipc_out},
67 midi_receiver_{midi_receiver}, midi_sender_{midi_sender}, profile_(profile),
68 profile_manager_(profile_manager), settings_manager_(settings_manager) {
69 setSize(kMainWidth, kMainHeight);
70}
71
72catch (const std::exception& e) {
73 rsj::ExceptionResponse(e, std::source_location::current());
74 throw;
75}
LrIpcOut & lr_ipc_out_
Definition MainComponent.h:96
MidiReceiver & midi_receiver_
Definition MainComponent.h:97
CommandTableModel command_table_model_
Definition MainComponent.h:74
ProfileManager & profile_manager_
Definition MainComponent.h:100
Profile & profile_
Definition MainComponent.h:99
MidiSender & midi_sender_
Definition MainComponent.h:98
SettingsManager & settings_manager_
Definition MainComponent.h:101
void ExceptionResponse(gsl::czstring id, gsl::czstring fu, const std::exception &e) noexcept

◆ ~MainContentComponent()

MainContentComponent::~MainContentComponent ( )
78{
80 juce::Timer::stopTimer();
81}
juce::Label profile_name_label_
Definition MainComponent.h:78
void SetDefaultProfile(const juce::String &default_profile)
Definition SettingsManager.h:65

◆ MainContentComponent() [2/3]

MainContentComponent::MainContentComponent ( const MainContentComponent other)
delete

◆ MainContentComponent() [3/3]

MainContentComponent::MainContentComponent ( MainContentComponent &&  other)
delete

Member Function Documentation

◆ AddComponent()

void MainContentComponent::AddComponent ( juce::Component &  component,
int  x,
int  y,
int  width,
int  height 
)
private
193{
194 component.setBounds(x, y, width, height);
195 ResizableLayout::addToLayout(&component, anchorMidLeft, anchorMidRight);
196 juce::Component::addAndMakeVisible(component);
197}

◆ DisconnectClicked()

void MainContentComponent::DisconnectClicked ( )
private
174{
175 if (disconnect_button_.getToggleState()) {
177 rsj::Log("Sending halted.", std::source_location::current());
178 }
179 else {
181 rsj::Log("Sending restarted.", std::source_location::current());
182 }
183}
void SendingRestart()
Definition LR_IPC_Out.cpp:77
void SendingStop()
Definition LR_IPC_Out.cpp:93
juce::TextButton disconnect_button_
Definition MainComponent.h:89
void Log(const juce::String &info, const std::source_location &location=std::source_location::current()) noexcept
Definition Misc.cpp:113

◆ handleAsyncUpdate()

void MainContentComponent::handleAsyncUpdate ( )
overrideprivate
407{
408 try {
409 /* Update the last command label and set its color to green */
410 command_label_.setText(last_command_, juce::NotificationType::dontSendNotification);
411 command_label_.setColour(juce::Label::backgroundColourId, juce::Colours::greenyellow);
412 juce::Timer::startTimer(1000);
413 /* Update the command table to add and/or select row corresponding to midi command */
414 command_table_.updateContent();
415 command_table_.selectRow(gsl::narrow_cast<int>(row_to_select_));
416 }
417 catch (const std::exception& e) {
418 rsj::ExceptionResponse(e, std::source_location::current());
419 throw;
420 }
421}
CommandTable command_table_
Definition MainComponent.h:73
juce::String last_command_
Definition MainComponent.h:88
juce::Label command_label_
Definition MainComponent.h:76
size_t row_to_select_
Definition MainComponent.h:102

◆ Init()

void MainContentComponent::Init ( )
200{
201 try {
205
206 /* Main title */
207 StandardLabelSettings(title_label_);
208 title_label_.setFont(juce::Font {juce::FontOptions(36.F, juce::Font::bold)});
209 title_label_.setComponentEffect(&title_shadow_);
210 AddComponent(title_label_, kMainLeft, 10, kFullWidth, 30);
211
212 /* Version label */
213 StandardLabelSettings(version_label_);
214 AddComponent(version_label_, kMainLeft, 40, kFullWidth, 10);
215
216 /* Connection status */
217 StandardLabelSettings(connection_label_);
218 connection_label_.setColour(juce::Label::textColourId, juce::Colours::black);
219 connection_label_.setColour(juce::Label::backgroundColourId, juce::Colours::red);
220 connection_label_.setJustificationType(juce::Justification::centred);
221 AddComponent(connection_label_, 200, 15, kConnectionLabelWidth, kStandardHeight);
222
223 /* Load button */
224 AddComponent(load_button_, kFirstButtonX, kTopButtonY, kButtonWidth, kStandardHeight);
225#if __cpp_lib_bind_front >= 202'306L
226 load_button_.onClick = std::bind_front<&MainContentComponent::LoadClicked>(this);
227#else
228 load_button_.onClick = std::bind_front(&MainContentComponent::LoadClicked, this);
229#endif
230
231 /* Save button */
232 AddComponent(save_button_, kSecondButtonX, kTopButtonY, kButtonWidth, kStandardHeight);
233#if __cpp_lib_bind_front >= 202'306L
234 save_button_.onClick = std::bind_front<&MainContentComponent::SaveProfile>(this);
235#else
236 save_button_.onClick = std::bind_front(&MainContentComponent::SaveProfile, this);
237#endif
238
239 /* Settings button */
240 AddComponent(settings_button_, kThirdButtonX, kTopButtonY, kButtonWidth, kStandardHeight);
241#if __cpp_lib_bind_front >= 202'306L
242 settings_button_.onClick = std::bind_front<&MainContentComponent::SettingsClicked>(this);
243#else
244 settings_button_.onClick = std::bind_front(&MainContentComponent::SettingsClicked, this);
245#endif
246
247 /* Command Table */
249 AddComponent(command_table_, kMainLeft, kCommandTableY, kFullWidth, kCommandTableHeight);
250
251 /* Profile name label */
252 StandardLabelSettings(profile_name_label_);
253 profile_name_label_.setColour(juce::Label::textColourId, juce::Colours::black);
254 profile_name_label_.setJustificationType(juce::Justification::centred);
255 AddComponent(profile_name_label_, kMainLeft, kProfileNameY, kLabelWidth, kStandardHeight);
256
257 /* Last MIDI command */
258 StandardLabelSettings(command_label_);
259 AddComponent(command_label_, kCommandLabelX, kCommandLabelY, kLabelWidth, kStandardHeight);
260
261 /* Remove row button */
262 AddComponent(remove_allrows_button_, kFirstButtonX, kBottomButtonY, kButtonWidth,
263 kStandardHeight);
264#if __cpp_lib_bind_front >= 202'306L
265 remove_allrows_button_.onClick =
266 std::bind_front<&MainContentComponent::RemoveAllRowsClicked>(this);
267#else
268 remove_allrows_button_.onClick =
269 std::bind_front(&MainContentComponent::RemoveAllRowsClicked, this);
270#endif
271
272 /* Rescan MIDI button */
273 AddComponent(rescan_button_, kSecondButtonX, kBottomButtonY, kButtonWidth, kStandardHeight);
274#if __cpp_lib_bind_front >= 202'306L
275 rescan_button_.onClick = std::bind_front<&MainContentComponent::RescanClicked>(this);
276#else
277 rescan_button_.onClick = std::bind_front(&MainContentComponent::RescanClicked, this);
278#endif
279
280 /* Disconnect button */
281 disconnect_button_.setClickingTogglesState(true);
282 AddComponent(disconnect_button_, kThirdButtonX, kBottomButtonY, kButtonWidth,
283 kStandardHeight);
284#if __cpp_lib_bind_front >= 202'306L
285 disconnect_button_.onClick = std::bind_front<&MainContentComponent::DisconnectClicked>(this);
286#else
287 disconnect_button_.onClick = std::bind_front(&MainContentComponent::DisconnectClicked, this);
288#endif
289
290 /* Delete unassigned rows */
291 AddComponent(remove_unassigned_button_, kFirstButtonX, kBottomButtonY2, kButtonWidth,
292 kStandardHeight);
293#if __cpp_lib_bind_front >= 202'306L
295 std::bind_front<&MainContentComponent::RemoveUnassignedClicked>(this);
296#else
298 std::bind_front(&MainContentComponent::RemoveUnassignedClicked, this);
299#endif
300
301 /* Try to load a default.xml if the user has not set a profile directory */
302 if (settings_manager_.GetProfileDirectory().isEmpty()) {
303 const auto filename {rsj::AppDataFilePath(kDefaultsFile)};
304 const auto default_profile {juce::File(filename.data())};
305 if (const auto parsed {juce::parseXML(default_profile)}) {
306 profile_.FromXml(parsed.get());
307 command_table_.updateContent();
308 }
309 }
310 else {
311 const auto last_prof {settings_manager_.GetDefaultProfile()};
312 if (last_prof != juce::String()) { profile_manager_.SwitchToProfile(last_prof); }
313 else { /* otherwise use the last profile from the profile directory */
315 }
316 }
317
318 /* turn it on */
319 ResizableLayout::activateLayout();
320 }
321 catch (const std::exception& e) {
322 rsj::ExceptionResponse(e, std::source_location::current());
323 throw;
324 }
325}
void AddCallback(_In_ T *const object, _In_ void(T::*const mf)(bool, bool))
Definition LR_IPC_Out.h:51
void AddComponent(juce::Component &component, int x, int y, int width, int height)
Definition MainComponent.cpp:191
juce::TextButton rescan_button_
Definition MainComponent.h:93
void SaveProfile() const
Definition MainComponent.cpp:327
void ProfileChanged(juce::XmlElement *xml_element, const juce::String &file_name)
Definition MainComponent.cpp:387
void RemoveAllRowsClicked()
Definition MainComponent.cpp:156
juce::Label version_label_
Definition MainComponent.h:81
void DisconnectClicked()
Definition MainComponent.cpp:173
juce::TextButton settings_button_
Definition MainComponent.h:95
juce::Label connection_label_
Definition MainComponent.h:77
void LrIpcOutCallback(bool, bool)
Definition MainComponent.cpp:378
juce::TextButton save_button_
Definition MainComponent.h:94
juce::DropShadowEffect title_shadow_
Definition MainComponent.h:75
juce::TextButton load_button_
Definition MainComponent.h:90
void MidiCmdCallback(rsj::MidiMessage mm)
Definition MainComponent.cpp:345
void RescanClicked()
Definition MainComponent.cpp:164
juce::Label title_label_
Definition MainComponent.h:79
juce::TextButton remove_allrows_button_
Definition MainComponent.h:91
juce::TextButton remove_unassigned_button_
Definition MainComponent.h:92
void LoadClicked()
Definition MainComponent.cpp:92
void SettingsClicked()
Definition MainComponent.cpp:137
void RemoveUnassignedClicked()
Definition MainComponent.cpp:185
void AddCallback(_In_ T *const object, _In_ void(T::*const mf)(rsj::MidiMessage))
Definition MIDIReceiver.h:49
void FromXml(const juce::XmlElement *root)
Definition Profile.cpp:36
void SwitchToProfile(int profile_index)
Definition ProfileManager.cpp:57
void AddCallback(_In_ T *const object, _In_ void(T::*const mf)(juce::XmlElement *, const juce::String &))
Definition ProfileManager.h:49
juce::String GetDefaultProfile() const noexcept
Definition SettingsManager.h:42
juce::String GetProfileDirectory() const noexcept
Definition SettingsManager.h:57
std::string AppDataFilePath(const std::string &file_name)

◆ LoadClicked()

void MainContentComponent::LoadClicked ( )
private
93{
94 try {
96 if (juce::NativeMessageBox::showYesNoBox(juce::AlertWindow::WarningIcon,
97 juce::translate("MIDI2LR profiles"),
98 juce::translate("Profile changed. Do you want to save your changes? If you "
99 "continue without saving, your changes will be lost."))) {
100 SaveProfile();
101 }
102 }
103 juce::File profile_directory {settings_manager_.GetProfileDirectory()};
104 const auto directory_saved {profile_directory.exists()};
105 if (!directory_saved) [[unlikely]] {
106 profile_directory = juce::File::getSpecialLocation(juce::File::userDocumentsDirectory);
107 }
108 juce::FileChooser chooser {juce::translate("Open profile"), profile_directory, "*.xml", true};
109 if (chooser.browseForFileToOpen()) {
110 if (const auto parsed {juce::parseXML(chooser.getResult())}) {
111 const auto new_profile {chooser.getResult()};
112 lr_ipc_out_.SendCommand(fmt::format(FMT_STRING("ChangedToFullPath {}\n"),
113 new_profile.getFullPathName().toStdString()));
114 profile_name_label_.setText(new_profile.getFileName(),
115 juce::NotificationType::dontSendNotification);
116 profile_.FromXml(parsed.get());
117 command_table_.updateContent();
118 command_table_.repaint();
119 if (!directory_saved) [[unlikely]] { /* haven't saved a directory yet */
121 new_profile.getParentDirectory().getFullPathName());
122 }
123 }
124 else {
125 rsj::Log(fmt::format(FMT_STRING("Unable to load profile {}."),
126 chooser.getResult().getFullPathName().toStdString()),
127 std::source_location::current());
128 }
129 }
130 }
131 catch (const std::exception& e) {
132 rsj::ExceptionResponse(e, std::source_location::current());
133 throw;
134 }
135}
void SendCommand(std::string &&command) const
Definition LR_IPC_Out.cpp:67
bool ProfileUnsaved() const
Definition Profile.h:139
void SetProfileDirectory(const juce::String &profile_directory)
Definition SettingsManager.h:81

◆ LrIpcOutCallback()

void MainContentComponent::LrIpcOutCallback ( bool  connected,
bool  sending_blocked 
)
private
379{
380 const juce::MessageManagerLock mm_lock; /* as not called in message loop */
381 const auto& [text, color] {kConnectionStatus.at({connected, sending_blocked})};
382 UpdateConnectionLabel(text, color);
383}
void UpdateConnectionLabel(const char *text, juce::Colour colour)
Definition MainComponent.cpp:363

◆ MidiCmdCallback()

void MainContentComponent::MidiCmdCallback ( rsj::MidiMessage  mm)
private
346{
347 try {
348 /* Display the MIDI parameters and add/highlight row in table corresponding to the message.
349 * msg is 1-based for channel, which display expects */
350 const rsj::MidiMessageId msg {mm};
351 last_command_ = fmt::format(FMT_STRING("{}: {}{} [{}]"), msg.channel, mm.message_type_byte,
352 msg.control_number, mm.value);
354 row_to_select_ = gsl::narrow_cast<size_t>(profile_.GetRowForMessage(msg));
355 triggerAsyncUpdate();
356 }
357 catch (const std::exception& e) {
358 rsj::ExceptionResponse(e, std::source_location::current());
359 throw;
360 }
361}
int GetRowForMessage(rsj::MidiMessageId message) const
Definition Profile.h:103
void InsertUnassigned(rsj::MidiMessageId message)
Definition Profile.cpp:116
MessageType message_type_byte
Definition MidiUtilities.h:124
int value
Definition MidiUtilities.h:127
Definition MidiUtilities.h:145

◆ operator=() [1/2]

MainContentComponent & MainContentComponent::operator= ( const MainContentComponent other)
delete

◆ operator=() [2/2]

MainContentComponent & MainContentComponent::operator= ( MainContentComponent &&  other)
delete

◆ paint()

void MainContentComponent::paint ( juce::Graphics &  g)
overrideprivate
341{ //-V2009 overridden method
342 g.fillAll(juce::Colours::white);
343}

◆ ProfileChanged()

void MainContentComponent::ProfileChanged ( juce::XmlElement *  xml_element,
const juce::String &  file_name 
)
private
389{ //-V2009 overridden method
390 try {
391 {
392 const juce::MessageManagerLock mm_lock;
393 profile_.FromXml(xml_element);
394 command_table_.updateContent();
395 profile_name_label_.setText(file_name, juce::NotificationType::dontSendNotification);
396 }
397 /* Send new CC parameters to MIDI Out devices */
398 lr_ipc_out_.SendCommand("FullRefresh 1\n");
399 }
400 catch (const std::exception& e) {
401 rsj::ExceptionResponse(e, std::source_location::current());
402 throw;
403 }
404}

◆ RemoveAllRowsClicked()

void MainContentComponent::RemoveAllRowsClicked ( )
private
157{
158 if (command_table_.getNumRows() > 0) {
160 command_table_.updateContent();
161 }
162}
void RemoveAllRows()
Definition Profile.cpp:132

◆ RemoveUnassignedClicked()

void MainContentComponent::RemoveUnassignedClicked ( )
private
186{
188 command_table_.updateContent();
189}
void RemoveUnassignedMessages()
Definition Profile.cpp:188

◆ RescanClicked()

void MainContentComponent::RescanClicked ( )
private
165{
166 /* Re-enumerate MIDI IN and OUT devices */
169 /* Send new CC parameters to MIDI Out devices */
170 lr_ipc_out_.SendCommand("FullRefresh 1\n");
171}
void RescanDevices()
Definition MIDIReceiver.cpp:68
void RescanDevices()
Definition MIDISender.cpp:119

◆ SaveProfile()

void MainContentComponent::SaveProfile ( ) const
328{
329 juce::File profile_directory {settings_manager_.GetProfileDirectory()};
330 if (!profile_directory.exists()) {
331 profile_directory = juce::File::getSpecialLocation(juce::File::userDocumentsDirectory);
332 }
333 juce::FileChooser chooser {juce::translate("Save profile"), profile_directory, "*.xml", true};
334 if (chooser.browseForFileToSave(true)) {
335 const auto selected_file {chooser.getResult().withFileExtension("xml")};
336 profile_.ToXmlFile(selected_file);
337 }
338}
void ToXmlFile(const juce::File &file)
Definition Profile.cpp:240

◆ SettingsClicked()

void MainContentComponent::SettingsClicked ( )
private
138{
139 try {
140 juce::DialogWindow::LaunchOptions dialog_options;
141 dialog_options.dialogTitle = juce::translate("Settings");
142 /* create new object */
143 auto component {std::make_unique<SettingsComponent>(settings_manager_)};
144 component->Init();
145 dialog_options.content.setOwned(component.release());
146 dialog_options.content->setSize(400, 300);
147 settings_dialog_.reset(dialog_options.create());
148 settings_dialog_->setVisible(true);
149 }
150 catch (const std::exception& e) {
151 rsj::ExceptionResponse(e, std::source_location::current());
152 throw;
153 }
154}
std::unique_ptr< juce::DialogWindow > settings_dialog_
Definition MainComponent.h:103

◆ timerCallback()

void MainContentComponent::timerCallback ( )
overrideprivate
424{
425 /* reset the command label's background to white */
426 command_label_.setColour(juce::Label::backgroundColourId, juce::Colours::white);
427 juce::Timer::stopTimer();
428}

◆ UpdateConnectionLabel()

void MainContentComponent::UpdateConnectionLabel ( const char *  text,
juce::Colour  colour 
)
private
364{
365 connection_label_.setText(juce::translate(text), juce::NotificationType::dontSendNotification);
366 connection_label_.setColour(juce::Label::backgroundColourId, colour);
367}

Member Data Documentation

◆ command_label_

juce::Label MainContentComponent::command_label_ {"Command", ""}
private
76{"Command", ""};

◆ command_table_

CommandTable MainContentComponent::command_table_ {"Table", nullptr}
private
73{"Table", nullptr};

◆ command_table_model_

CommandTableModel MainContentComponent::command_table_model_
private

◆ connection_label_

juce::Label MainContentComponent::connection_label_ {"Connection", juce::translate("Not connected to Lightroom")}
private
77{"Connection", juce::translate("Not connected to Lightroom")};

◆ disconnect_button_

juce::TextButton MainContentComponent::disconnect_button_ {juce::translate("Halt sending to Lightroom")}
private
89{juce::translate("Halt sending to Lightroom")};

◆ last_command_

juce::String MainContentComponent::last_command_
private

◆ load_button_

juce::TextButton MainContentComponent::load_button_ {juce::translate("Load")}
private
90{juce::translate("Load")};

◆ lr_ipc_out_

LrIpcOut& MainContentComponent::lr_ipc_out_
private

◆ midi_receiver_

MidiReceiver& MainContentComponent::midi_receiver_
private

◆ midi_sender_

MidiSender& MainContentComponent::midi_sender_
private

◆ profile_

Profile& MainContentComponent::profile_
private

◆ profile_manager_

ProfileManager& MainContentComponent::profile_manager_
private

◆ profile_name_label_

juce::Label MainContentComponent::profile_name_label_ {"ProfileNameLabel", ""}
private
78{"ProfileNameLabel", ""};

◆ remove_allrows_button_

juce::TextButton MainContentComponent::remove_allrows_button_ {juce::translate("Clear ALL rows")}
private
91{juce::translate("Clear ALL rows")};

◆ remove_unassigned_button_

juce::TextButton MainContentComponent::remove_unassigned_button_ {juce::translate("Remove unassigned rows")}
private
92{juce::translate("Remove unassigned rows")};

◆ rescan_button_

juce::TextButton MainContentComponent::rescan_button_ {juce::translate("Rescan MIDI devices")}
private
93{juce::translate("Rescan MIDI devices")};

◆ row_to_select_

size_t MainContentComponent::row_to_select_ {0}
private
102{0};

◆ save_button_

juce::TextButton MainContentComponent::save_button_ {juce::translate("Save")}
private
94{juce::translate("Save")};

◆ settings_button_

juce::TextButton MainContentComponent::settings_button_ {juce::translate("Settings")}
private
95{juce::translate("Settings")};

◆ settings_dialog_

std::unique_ptr<juce::DialogWindow> MainContentComponent::settings_dialog_
private

◆ settings_manager_

SettingsManager& MainContentComponent::settings_manager_
private

◆ title_label_

juce::Label MainContentComponent::title_label_ {"Title", "MIDI2LR"}
private
79{"Title", "MIDI2LR"};

◆ title_shadow_

juce::DropShadowEffect MainContentComponent::title_shadow_
private

◆ version_label_

juce::Label MainContentComponent::version_label_
private
Initial value:
{"Version", juce::translate("Version ") + juce::String {
ProjectInfo::versionString
}}
81 {"Version", juce::translate("Version ") + juce::String {
82 ProjectInfo::versionString
83 }};

The documentation for this class was generated from the following files: