New upstream version 0.22.0
authorDennis Braun <d_braun@kabelmail.de>
Mon, 13 Jun 2022 20:45:45 +0000 (22:45 +0200)
committerDennis Braun <d_braun@kabelmail.de>
Mon, 13 Jun 2022 20:45:45 +0000 (22:45 +0200)
128 files changed:
CMakeLists.txt
ChangeLog
extras/com.giadamusic.Giada.desktop
src/core/channels/channel.cpp
src/core/channels/channel.h
src/core/channels/channelShared.cpp [new file with mode: 0644]
src/core/channels/channelShared.h [new file with mode: 0644]
src/core/channels/midiController.cpp
src/core/channels/midiController.h
src/core/channels/midiReceiver.cpp
src/core/channels/midiReceiver.h
src/core/channels/midiSender.cpp
src/core/channels/midiSender.h
src/core/channels/sampleReactor.cpp
src/core/channels/sampleReactor.h
src/core/conf.cpp
src/core/conf.h
src/core/const.h
src/core/engine.cpp
src/core/engine.h
src/core/eventDispatcher.cpp
src/core/eventDispatcher.h
src/core/init.cpp
src/core/kernelMidi.cpp
src/core/kernelMidi.h
src/core/midiDispatcher.cpp
src/core/midiMapper.cpp
src/core/midiMapper.h
src/core/patch.cpp
src/core/plugins/pluginManager.cpp
src/core/waveManager.cpp
src/glue/channel.cpp
src/glue/config.cpp
src/glue/config.h
src/glue/io.cpp
src/glue/layout.cpp
src/glue/main.cpp
src/glue/recorder.cpp
src/glue/sampleEditor.cpp
src/glue/storage.cpp
src/gui/dialogs/about.cpp
src/gui/dialogs/about.h
src/gui/dialogs/actionEditor/baseActionEditor.cpp
src/gui/dialogs/actionEditor/sampleActionEditor.cpp
src/gui/dialogs/beatsInput.cpp
src/gui/dialogs/beatsInput.h
src/gui/dialogs/bpmInput.cpp
src/gui/dialogs/bpmInput.h
src/gui/dialogs/browser/browserBase.cpp
src/gui/dialogs/browser/browserDir.cpp
src/gui/dialogs/browser/browserLoad.cpp
src/gui/dialogs/browser/browserSave.cpp
src/gui/dialogs/channelNameInput.cpp
src/gui/dialogs/channelNameInput.h
src/gui/dialogs/config.cpp
src/gui/dialogs/keyGrabber.cpp
src/gui/dialogs/mainWindow.cpp
src/gui/dialogs/midiIO/midiInputChannel.cpp
src/gui/dialogs/midiIO/midiInputMaster.cpp
src/gui/dialogs/midiIO/midiOutputBase.cpp
src/gui/dialogs/midiIO/midiOutputBase.h
src/gui/dialogs/midiIO/midiOutputMidiCh.cpp
src/gui/dialogs/midiIO/midiOutputSampleCh.cpp
src/gui/dialogs/missingAssets.cpp
src/gui/dialogs/pluginChooser.cpp
src/gui/dialogs/pluginList.cpp
src/gui/dialogs/sampleEditor.cpp
src/gui/dialogs/warnings.cpp
src/gui/elems/actionEditor/gridTool.cpp
src/gui/elems/actionEditor/sampleActionEditor.cpp
src/gui/elems/actionEditor/velocityEditor.cpp
src/gui/elems/basics/scroll.cpp
src/gui/elems/basics/scroll.h
src/gui/elems/basics/statusButton.cpp
src/gui/elems/basics/statusButton.h
src/gui/elems/config/stringMenu.cpp [new file with mode: 0644]
src/gui/elems/config/stringMenu.h [new file with mode: 0644]
src/gui/elems/config/tabAudio.cpp
src/gui/elems/config/tabBehaviors.cpp
src/gui/elems/config/tabBindings.cpp
src/gui/elems/config/tabMidi.cpp
src/gui/elems/config/tabMidi.h
src/gui/elems/config/tabMisc.cpp
src/gui/elems/config/tabMisc.h
src/gui/elems/config/tabPlugins.cpp
src/gui/elems/fileBrowser.cpp
src/gui/elems/fileBrowser.h
src/gui/elems/keyBinder.cpp
src/gui/elems/mainWindow/keyboard/column.cpp
src/gui/elems/mainWindow/keyboard/keyboard.cpp
src/gui/elems/mainWindow/keyboard/keyboard.h
src/gui/elems/mainWindow/keyboard/midiActivity.cpp
src/gui/elems/mainWindow/keyboard/midiChannel.cpp
src/gui/elems/mainWindow/keyboard/sampleChannel.cpp
src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp
src/gui/elems/mainWindow/mainIO.cpp
src/gui/elems/mainWindow/mainIO.h
src/gui/elems/mainWindow/mainMenu.cpp
src/gui/elems/mainWindow/mainMenu.h
src/gui/elems/mainWindow/mainTimer.cpp
src/gui/elems/mainWindow/mainTimer.h
src/gui/elems/mainWindow/mainTransport.cpp
src/gui/elems/mainWindow/mainTransport.h
src/gui/elems/mainWindow/sequencer.cpp
src/gui/elems/mainWindow/sequencer.h
src/gui/elems/midiIO/midiLearner.cpp
src/gui/elems/midiIO/midiLearnerPack.cpp
src/gui/elems/midiIO/midiLearnerPack.h
src/gui/elems/plugin/pluginBrowser.cpp
src/gui/elems/plugin/pluginElement.cpp
src/gui/elems/sampleEditor/boostTool.cpp [deleted file]
src/gui/elems/sampleEditor/boostTool.h [deleted file]
src/gui/elems/sampleEditor/panTool.cpp
src/gui/elems/sampleEditor/pitchTool.cpp
src/gui/elems/sampleEditor/rangeTool.cpp
src/gui/elems/sampleEditor/shiftTool.cpp
src/gui/elems/sampleEditor/volumeTool.cpp
src/gui/elems/sampleEditor/waveTools.cpp
src/gui/langMapper.cpp [new file with mode: 0644]
src/gui/langMapper.h [new file with mode: 0644]
src/gui/ui.cpp
src/gui/ui.h
src/mapper.cpp [new file with mode: 0644]
src/mapper.h [new file with mode: 0644]
src/utils/fs.cpp
src/utils/fs.h
src/utils/log.cpp
vcpkg.json [new file with mode: 0644]

index 5ec69d1a8bb3865fa58214c39c06911b73ccce3c..e66f0f1589e7e0d69aad059fb82b7371466c5ccb 100644 (file)
@@ -33,6 +33,7 @@ project(giada LANGUAGES CXX)
 
 list(APPEND SOURCES
        src/main.cpp
+       src/mapper.cpp
        src/core/engine.cpp
        src/core/worker.cpp
        src/core/eventDispatcher.cpp
@@ -77,6 +78,7 @@ list(APPEND SOURCES
        src/core/channels/midiSender.cpp
        src/core/channels/midiReceiver.cpp
        src/core/channels/channel.cpp
+       src/core/channels/channelShared.cpp
        src/core/channels/channelManager.cpp
        src/core/model/sequencer.cpp
        src/core/model/mixer.cpp
@@ -99,6 +101,7 @@ list(APPEND SOURCES
        src/gui/dialogs/window.cpp
        src/gui/dispatcher.cpp
        src/gui/updater.cpp
+       src/gui/langMapper.cpp
        src/gui/drawing.cpp
        src/gui/dialogs/progress.cpp
        src/gui/dialogs/keyGrabber.cpp
@@ -139,7 +142,6 @@ list(APPEND SOURCES
        src/gui/elems/sampleEditor/waveform.cpp
        src/gui/elems/sampleEditor/waveTools.cpp
        src/gui/elems/sampleEditor/volumeTool.cpp
-       src/gui/elems/sampleEditor/boostTool.cpp
        src/gui/elems/sampleEditor/panTool.cpp
        src/gui/elems/sampleEditor/pitchTool.cpp
        src/gui/elems/sampleEditor/rangeTool.cpp
@@ -177,6 +179,7 @@ list(APPEND SOURCES
        src/gui/elems/config/tabBehaviors.cpp
        src/gui/elems/config/tabPlugins.cpp
        src/gui/elems/config/tabBindings.cpp
+       src/gui/elems/config/stringMenu.cpp
        src/gui/elems/basics/scroll.cpp
        src/gui/elems/basics/pack.cpp
        src/gui/elems/basics/group.cpp
@@ -303,14 +306,15 @@ if (NOT RtMidi_FOUND)
                message(FATAL_ERROR "Can't find RtMidi, aborting.")
        endif()
 
-       # RtMidi header path may vary across OSes, so a fix is needed.
-       # TODO - Find a way to avoid this additional step
-
-       find_path(LIBRARY_RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES rtmidi)
-       list(APPEND INCLUDE_DIRS ${LIBRARY_RTMIDI_INCLUDE_DIR})
        message("RtMidi library found in " ${RtMidi_DIR})
 endif()
 
+# RtMidi header path may vary across OSes, so a fix is needed.
+# TODO - Find a way to avoid this additional step
+
+find_path(LIBRARY_RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES rtmidi)
+list(APPEND INCLUDE_DIRS ${LIBRARY_RTMIDI_INCLUDE_DIR})
+
 # FLTK 
 
 set(FLTK_SKIP_FLUID TRUE)  # Don't search for FLTK's fluid
@@ -386,6 +390,18 @@ else()
        message("Libsamplerate library found in " ${LIBRARY_SAMPLERATE})
 endif()
 
+# fmt
+
+find_package(fmt REQUIRED)
+list(APPEND LIBRARIES fmt::fmt)
+
+# nlohmann_json (embedded as git submodule)
+
+set(JSON_Install OFF CACHE INTERNAL "") # No need to install it
+set(JSON_BuildTests OFF CACHE INTERNAL "") # Don't build tests
+add_subdirectory(src/deps/json)
+list(APPEND LIBRARIES nlohmann_json::nlohmann_json)
+
 # Catch (if tests enabled)
 
 if (WITH_TESTS)
index 77bd5923ed5759b11fa76f665327494da9518b6b..f36ee3a604344162497894018f268ef6e3bce90e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
+0.22.0 --- 2022 . 06 .  13
+- Multi-language support via langmaps (#34)
+- Add new 'fmt' dependency
+- Add vcpkg.json manifest file
+- Log compiled RtMidi APIs on startup
+- Fix missing header with RtMidi 5.0.0
+- Fix Stream Linker button not working (#585)
+- Minor code refactoring and cleanups
+
+
+0.21.0 --- 2022 . 04 . 01
+- Custom keyboard mappings for global actions (#213)
+- Pressing 'Esc' key no longer closes windows
+- Resizable Configuration window
+- Shut down the main UI nicely when closing a project or loading a new one
+- Prevent crashes when loading a new project by cleaning up the data model 
+- Fix wrong plug-in processing where the local plug-in buffer was incorrectly 
+  deleted in case of instruments (#563)
+- Lots of UI code modernizations and cleanups
+- [Windows] Fix several assertions and MSVC warnings
+
+
 0.20.1 --- 2022 . 02 . 21
 - New MIDI I/O activity LEDs on channels (#143)
 - New "Missing Assets" alert window (#344)
index b9d33b5039e786bbe5fa61489ddad9428b5aec5a..3c8158002e80ca2806559049f9b4e077e43d2801 100644 (file)
@@ -2,11 +2,17 @@
 Version=1.0
 Type=Application
 Name=Giada
-Name[es]=Giada
 GenericName=Drum machine and loop sequencer
+Comment=Drum machine and loop sequencer
+GenericName[de]=Drum Maschine und Loop Sequenzer
 GenericName[es]=Caja de ritmos y secuenciador de loops
+GenericName[fr]=Boîte Ã  rythme et séquenceur de boucle
+Comment=Drum machine and loop sequencer
+Comment[de]=Drum Maschine und Loop Sequenzer
+Comment[es]=Caja de ritmos y secuenciador de loops
+Comment[fr]=Boîte Ã  rythme et séquenceur de boucle
 Exec=giada %f
 Terminal=false
 Icon=com.giadamusic.Giada
 Categories=Music;AudioVideo;Audio;Midi;X-Digital_Processing;X-Jack;X-MIDI;
-Keywords=Giada;
+Keywords=midi;jackd;alsa;pulse;audio;sound;loop;
index 7cf70817500d7c2909ca4bf9c24b33389a3ffc4f..ff92e4d73fc551b4f04274fa9f08bc0ad34d2ab5 100644 (file)
@@ -60,13 +60,6 @@ mcl::AudioBuffer::Pan calcPanning_(float pan)
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-ChannelShared::ChannelShared(Frame bufferSize)
-: audioBuffer(bufferSize, G_MAX_IO_CHANS)
-{
-}
-
-/* -------------------------------------------------------------------------- */
-
 Channel::Channel(ChannelType type, ID id, ID columnId, ChannelShared& s)
 : shared(&s)
 , id(id)
@@ -324,14 +317,14 @@ void Channel::advance(const Sequencer::EventBuffer& events, Range<Frame> block,
        for (const Sequencer::Event& e : events)
        {
                if (midiController)
-                       midiController->advance(*this, e);
+                       midiController->advance(shared->playStatus, e);
                if (samplePlayer)
                        sampleAdvancer->advance(*this, e);
-               if (midiSender)
-                       midiSender->advance(*this, e);
+               if (midiSender && isPlaying() && !isMuted())
+                       midiSender->advance(id, e);
 #ifdef WITH_VST
-               if (midiReceiver)
-                       midiReceiver->advance(*this, e);
+               if (midiReceiver && isPlaying())
+                       midiReceiver->advance(id, shared->midiQueue, e);
 #endif
        }
 }
@@ -347,9 +340,9 @@ void Channel::react(const EventDispatcher::EventBuffer& events)
 
                react(e);
                if (midiController)
-                       midiController->react(*this, e);
-               if (midiSender)
-                       midiSender->react(*this, e);
+                       midiController->react(shared->playStatus, e);
+               if (midiSender && isPlaying() && !isMuted())
+                       midiSender->react(e);
                if (samplePlayer)
                        samplePlayer->react(e);
                if (midiActionRecorder)
@@ -358,10 +351,11 @@ void Channel::react(const EventDispatcher::EventBuffer& events)
                        sampleActionRecorder->react(*this, e, g_engine.conf.data.treatRecsAsLoops,
                            g_engine.sequencer.isRunning(), g_engine.recorder.canRecordActions());
                if (sampleReactor)
-                       sampleReactor->react(*this, e, g_engine.sequencer, g_engine.conf.data);
+                       sampleReactor->react(*this, e, g_engine.conf.data.chansStopOnSeqHalt,
+                           g_engine.sequencer.canQuantize());
 #ifdef WITH_VST
                if (midiReceiver)
-                       midiReceiver->react(*this, e);
+                       midiReceiver->react(shared->midiQueue, e);
 #endif
        }
 }
@@ -457,7 +451,7 @@ void Channel::renderChannel(mcl::AudioBuffer& out, mcl::AudioBuffer& in, bool au
 
 #ifdef WITH_VST
        if (midiReceiver)
-               midiReceiver->render(*this, g_engine.pluginHost);
+               midiReceiver->render(*shared, plugins, g_engine.pluginHost);
        else if (plugins.size() > 0)
                g_engine.pluginHost.processStack(shared->audioBuffer, plugins, nullptr);
 #endif
index 020ba9eb2f20cd6154d8a1388026316f217ee933..4926c1f931a02da736da5bd8740f3e7eb2e3caea 100644 (file)
@@ -32,6 +32,7 @@
 #include "deps/juce-config.h"
 #endif
 #include "core/channels/audioReceiver.h"
+#include "core/channels/channelShared.h"
 #include "core/channels/midiActionRecorder.h"
 #include "core/channels/midiController.h"
 #include "core/channels/midiLearner.h"
 namespace giada::m
 {
 class Plugin;
-
-struct ChannelShared final
-{
-       ChannelShared(Frame bufferSize);
-
-       mcl::AudioBuffer audioBuffer;
-#ifdef WITH_VST
-       juce::MidiBuffer     midiBuffer;
-       Queue<MidiEvent, 32> midiQueue;
-#endif
-
-       WeakAtomic<Frame>         tracker     = 0;
-       WeakAtomic<ChannelStatus> playStatus  = ChannelStatus::OFF;
-       WeakAtomic<ChannelStatus> recStatus   = ChannelStatus::OFF;
-       WeakAtomic<bool>          readActions = false;
-
-       std::optional<Quantizer> quantizer;
-
-       /* Optional render queue for sample-based channels. Used by SampleReactor
-       and SampleAdvancer to instruct SamplePlayer how to render audio. */
-
-       std::optional<Queue<SamplePlayer::Render, 2>> renderQueue = {};
-
-       /* Optional resampler for sample-based channels. Unfortunately a Resampler
-       object (based on libsamplerate) doesn't like to get copied while rendering
-       audio, so can't live inside WaveReader object (which is copied on model 
-       changes by the Swapper mechanism). Let's put it in the shared state here. */
-
-       std::optional<Resampler> resampler = {};
-};
-
-/* -------------------------------------------------------------------------- */
-
 class Channel final
 {
 public:
diff --git a/src/core/channels/channelShared.cpp b/src/core/channels/channelShared.cpp
new file mode 100644 (file)
index 0000000..afbf1da
--- /dev/null
@@ -0,0 +1,35 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "core/channels/channelShared.h"
+
+namespace giada::m
+{
+ChannelShared::ChannelShared(Frame bufferSize)
+: audioBuffer(bufferSize, G_MAX_IO_CHANS)
+{
+}
+} // namespace giada::m
\ No newline at end of file
diff --git a/src/core/channels/channelShared.h b/src/core/channels/channelShared.h
new file mode 100644 (file)
index 0000000..a77c54a
--- /dev/null
@@ -0,0 +1,77 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_CHANNELSHARED_H
+#define G_CHANNELSHARED_H
+
+#include <optional>
+#ifdef WITH_VST
+#include "deps/juce-config.h"
+#endif
+#include "core/channels/samplePlayer.h"
+#include "core/const.h"
+#include "core/midiEvent.h"
+#include "core/queue.h"
+#include "core/resampler.h"
+#include "deps/mcl-audio-buffer/src/audioBuffer.hpp"
+
+namespace giada::m
+{
+struct ChannelShared final
+{
+       using MidiQueue   = Queue<MidiEvent, 32>;
+       using RenderQueue = Queue<SamplePlayer::Render, 2>;
+
+       ChannelShared(Frame bufferSize);
+
+       mcl::AudioBuffer audioBuffer;
+#ifdef WITH_VST
+       juce::MidiBuffer midiBuffer;
+       MidiQueue        midiQueue;
+#endif
+
+       WeakAtomic<Frame>         tracker     = 0;
+       WeakAtomic<ChannelStatus> playStatus  = ChannelStatus::OFF;
+       WeakAtomic<ChannelStatus> recStatus   = ChannelStatus::OFF;
+       WeakAtomic<bool>          readActions = false;
+
+       std::optional<Quantizer> quantizer;
+
+       /* Optional render queue for sample-based channels. Used by SampleReactor
+       and SampleAdvancer to instruct SamplePlayer how to render audio. */
+
+       std::optional<RenderQueue> renderQueue = {};
+
+       /* Optional resampler for sample-based channels. Unfortunately a Resampler
+       object (based on libsamplerate) doesn't like to get copied while rendering
+       audio, so can't live inside WaveReader object (which is copied on model 
+       changes by the Swapper mechanism). Let's put it in the shared state here. */
+
+       std::optional<Resampler> resampler = {};
+};
+} // namespace giada::m
+
+#endif
index 3ad920d3b5a9ea434f32d32605eab7c2d2623cfa..29fdb337caec6d3e085d0f4bf053dbed72d77259 100644 (file)
  * -------------------------------------------------------------------------- */
 
 #include "midiController.h"
-#include "core/channels/channel.h"
-#include "core/conf.h"
-#include <cassert>
 
 namespace giada::m
 {
-void MidiController::react(Channel& ch, const EventDispatcher::Event& e) const
+void MidiController::react(WeakAtomic<ChannelStatus>& a_playStatus, const EventDispatcher::Event& e) const
 {
+       const ChannelStatus playStatus = a_playStatus.load();
+
        switch (e.type)
        {
        case EventDispatcher::EventType::KEY_PRESS:
-               ch.shared->playStatus.store(press(ch));
+               a_playStatus.store(press(playStatus));
                break;
 
        case EventDispatcher::EventType::KEY_KILL:
        case EventDispatcher::EventType::SEQUENCER_STOP:
-               ch.shared->playStatus.store(ChannelStatus::OFF);
+               a_playStatus.store(ChannelStatus::OFF);
                break;
 
        case EventDispatcher::EventType::SEQUENCER_REWIND:
-               ch.shared->playStatus.store(onFirstBeat(ch));
+               a_playStatus.store(onFirstBeat(playStatus));
 
        default:
                break;
@@ -54,18 +53,17 @@ void MidiController::react(Channel& ch, const EventDispatcher::Event& e) const
 
 /* -------------------------------------------------------------------------- */
 
-void MidiController::advance(const Channel& ch, const Sequencer::Event& e) const
+void MidiController::advance(WeakAtomic<ChannelStatus>& a_playStatus, const Sequencer::Event& e) const
 {
-       if (e.type == Sequencer::EventType::FIRST_BEAT)
-               ch.shared->playStatus.store(onFirstBeat(ch));
+       if (e.type != Sequencer::EventType::FIRST_BEAT)
+               return;
+       a_playStatus.store(onFirstBeat(a_playStatus.load()));
 }
 
 /* -------------------------------------------------------------------------- */
 
-ChannelStatus MidiController::onFirstBeat(const Channel& ch) const
+ChannelStatus MidiController::onFirstBeat(ChannelStatus playStatus) const
 {
-       ChannelStatus playStatus = ch.shared->playStatus.load();
-
        if (playStatus == ChannelStatus::ENDING)
                playStatus = ChannelStatus::OFF;
        else if (playStatus == ChannelStatus::WAIT)
@@ -76,10 +74,8 @@ ChannelStatus MidiController::onFirstBeat(const Channel& ch) const
 
 /* -------------------------------------------------------------------------- */
 
-ChannelStatus MidiController::press(const Channel& ch) const
+ChannelStatus MidiController::press(ChannelStatus playStatus) const
 {
-       ChannelStatus playStatus = ch.shared->playStatus.load();
-
        switch (playStatus)
        {
        case ChannelStatus::PLAY:
index 61c701e541226bfaae7e71dffb36084953bd1eb3..a975f2059bba0fc869511c6eda704cca5fe6c09b 100644 (file)
 #ifndef G_CHANNEL_MIDI_CONTROLLER_H
 #define G_CHANNEL_MIDI_CONTROLLER_H
 
+#include "core/eventDispatcher.h"
 #include "core/sequencer.h"
 
 namespace giada::m
 {
-class Channel;
 class MidiController final
 {
 public:
-       void advance(const Channel& ch, const Sequencer::Event& e) const;
-       void react(Channel& ch, const EventDispatcher::Event& e) const;
+       void advance(WeakAtomic<ChannelStatus>&, const Sequencer::Event& e) const;
+       void react(WeakAtomic<ChannelStatus>&, const EventDispatcher::Event& e) const;
 
 private:
-       ChannelStatus onFirstBeat(const Channel& ch) const;
-       ChannelStatus press(const Channel& ch) const;
+       ChannelStatus onFirstBeat(ChannelStatus) const;
+       ChannelStatus press(ChannelStatus) const;
 };
 } // namespace giada::m
 
index 599f2ca5dd9a6c19b4ad1ecd98297411025f3e11..da7c47f3cfdcb5812f7f5ecf1359b5cb0ec8a067 100644 (file)
 #ifdef WITH_VST
 
 #include "midiReceiver.h"
-#include "core/channels/channel.h"
 #include "core/eventDispatcher.h"
-#include "core/mixer.h"
 #include "core/plugins/pluginHost.h"
 
 namespace giada::m
 {
-void MidiReceiver::react(const Channel& ch, const EventDispatcher::Event& e) const
+void MidiReceiver::react(ChannelShared::MidiQueue& midiQueue, const EventDispatcher::Event& e) const
 {
        switch (e.type)
        {
        case EventDispatcher::EventType::MIDI:
-               parseMidi(ch, std::get<Action>(e.data).event);
+               parseMidi(midiQueue, std::get<Action>(e.data).event);
                break;
 
        case EventDispatcher::EventType::KEY_KILL:
        case EventDispatcher::EventType::SEQUENCER_STOP:
        case EventDispatcher::EventType::SEQUENCER_REWIND:
-               sendToPlugins(ch, MidiEvent(G_MIDI_ALL_NOTES_OFF), 0);
+               sendToPlugins(midiQueue, MidiEvent(G_MIDI_ALL_NOTES_OFF), 0);
                break;
 
        default:
@@ -55,43 +53,44 @@ void MidiReceiver::react(const Channel& ch, const EventDispatcher::Event& e) con
 
 /* -------------------------------------------------------------------------- */
 
-void MidiReceiver::advance(const Channel& ch, const Sequencer::Event& e) const
+void MidiReceiver::advance(ID channelId, ChannelShared::MidiQueue& midiQueue, const Sequencer::Event& e) const
 {
-       if (e.type == Sequencer::EventType::ACTIONS && ch.isPlaying())
-               for (const Action& action : *e.actions)
-                       if (action.channelId == ch.id)
-                               sendToPlugins(ch, action.event, e.delta);
+       if (e.type != Sequencer::EventType::ACTIONS)
+               return;
+       for (const Action& action : *e.actions)
+               if (action.channelId == channelId)
+                       sendToPlugins(midiQueue, action.event, e.delta);
 }
 
 /* -------------------------------------------------------------------------- */
 
-void MidiReceiver::render(const Channel& ch, PluginHost& pluginHost) const
+void MidiReceiver::render(ChannelShared& shared, const std::vector<Plugin*>& plugins, PluginHost& pluginHost) const
 {
-       ch.shared->midiBuffer.clear();
+       shared.midiBuffer.clear();
 
        MidiEvent e;
-       while (ch.shared->midiQueue.pop(e))
+       while (shared.midiQueue.pop(e))
        {
                juce::MidiMessage message = juce::MidiMessage(
                    e.getStatus(),
                    e.getNote(),
                    e.getVelocity());
-               ch.shared->midiBuffer.addEvent(message, e.getDelta());
+               shared.midiBuffer.addEvent(message, e.getDelta());
        }
 
-       pluginHost.processStack(ch.shared->audioBuffer, ch.plugins, &ch.shared->midiBuffer);
+       pluginHost.processStack(shared.audioBuffer, plugins, &shared.midiBuffer);
 }
 
 /* -------------------------------------------------------------------------- */
 
-void MidiReceiver::sendToPlugins(const Channel& ch, const MidiEvent& e, Frame localFrame) const
+void MidiReceiver::sendToPlugins(ChannelShared::MidiQueue& midiQueue, const MidiEvent& e, Frame localFrame) const
 {
-       ch.shared->midiQueue.push(MidiEvent(e.getRaw(), localFrame));
+       midiQueue.push(MidiEvent(e.getRaw(), localFrame));
 }
 
 /* -------------------------------------------------------------------------- */
 
-void MidiReceiver::parseMidi(const Channel& ch, const MidiEvent& e) const
+void MidiReceiver::parseMidi(ChannelShared::MidiQueue& midiQueue, const MidiEvent& e) const
 {
        /* Now all messages are turned into Channel-0 messages. Giada doesn't care 
        about holding MIDI channel information. Moreover, having all internal 
@@ -99,7 +98,7 @@ void MidiReceiver::parseMidi(const Channel& ch, const MidiEvent& e) const
 
        MidiEvent flat(e);
        flat.setChannel(0);
-       sendToPlugins(ch, flat, /*delta=*/0);
+       sendToPlugins(midiQueue, flat, /*delta=*/0);
 }
 } // namespace giada::m
 
index 4f8fdb5cfc9e065a9509937cfc7bce21a48bfe40..c28fefaad2fa2c1e1d74b22cd9d987df12744905 100644 (file)
 
 #ifdef WITH_VST
 
+#include "core/channels/channelShared.h"
 #include "core/sequencer.h"
 
 namespace giada::m
 {
 class PluginHost;
-class Channel;
+class Plugin;
 class MidiReceiver final
 {
 public:
-       void react(const Channel& ch, const EventDispatcher::Event& e) const;
-       void advance(const Channel& ch, const Sequencer::Event& e) const;
-       void render(const Channel& ch, PluginHost& plugiHost) const;
+       void react(ChannelShared::MidiQueue&, const EventDispatcher::Event&) const;
+       void advance(ID channelId, ChannelShared::MidiQueue&, const Sequencer::Event&) const;
+       void render(ChannelShared&, const std::vector<Plugin*>&, PluginHost&) const;
 
 private:
-       void sendToPlugins(const Channel& ch, const MidiEvent& e, Frame localFrame) const;
-       void parseMidi(const Channel& ch, const MidiEvent& e) const;
+       void sendToPlugins(ChannelShared::MidiQueue&, const MidiEvent&, Frame localFrame) const;
+       void parseMidi(ChannelShared::MidiQueue&, const MidiEvent&) const;
 };
 } // namespace giada::m
 
index 6eee0baebe0c90b99b7ba463122b0b2824429a67..4f93a3a02a77df56e5a4c425de044ef1ffed713e 100644 (file)
@@ -25,7 +25,6 @@
  * -------------------------------------------------------------------------- */
 
 #include "core/channels/midiSender.h"
-#include "core/channels/channel.h"
 #include "core/kernelMidi.h"
 #include "core/mixer.h"
 
@@ -50,9 +49,9 @@ MidiSender::MidiSender(const Patch::Channel& p, KernelMidi& k)
 
 /* -------------------------------------------------------------------------- */
 
-void MidiSender::react(const Channel& ch, const EventDispatcher::Event& e)
+void MidiSender::react(const EventDispatcher::Event& e)
 {
-       if (!ch.isPlaying() || !enabled || ch.isMuted())
+       if (!enabled)
                return;
 
        if (e.type == EventDispatcher::EventType::KEY_KILL ||
@@ -62,12 +61,12 @@ void MidiSender::react(const Channel& ch, const EventDispatcher::Event& e)
 
 /* -------------------------------------------------------------------------- */
 
-void MidiSender::advance(const Channel& ch, const Sequencer::Event& e) const
+void MidiSender::advance(ID channelId, const Sequencer::Event& e) const
 {
-       if (!ch.isPlaying() || !enabled || ch.isMuted())
+       if (!enabled)
                return;
        if (e.type == Sequencer::EventType::ACTIONS)
-               parseActions(ch, *e.actions);
+               parseActions(channelId, *e.actions);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -83,10 +82,10 @@ void MidiSender::send(MidiEvent e) const
 
 /* -------------------------------------------------------------------------- */
 
-void MidiSender::parseActions(const Channel& ch, const std::vector<Action>& as) const
+void MidiSender::parseActions(ID channelId, const std::vector<Action>& as) const
 {
        for (const Action& a : as)
-               if (a.channelId == ch.id)
+               if (a.channelId == channelId)
                        send(a.event);
 }
 } // namespace giada::m
\ No newline at end of file
index 140f29127926f7d21501426f02f1c226575d8a3f..7076164a22c4374a3df65705641c1b4fad225dd3 100644 (file)
@@ -33,7 +33,6 @@
 namespace giada::m
 {
 class KernelMidi;
-class Channel;
 class MidiSender final
 {
 public:
@@ -41,8 +40,8 @@ public:
        MidiSender(const Patch::Channel& p, KernelMidi&);
        MidiSender(const MidiSender& o) = default;
 
-       void react(const Channel& ch, const EventDispatcher::Event& e);
-       void advance(const Channel& ch, const Sequencer::Event& e) const;
+       void react(const EventDispatcher::Event& e);
+       void advance(ID channelId, const Sequencer::Event& e) const;
 
        KernelMidi* kernelMidi;
 
@@ -63,7 +62,7 @@ public:
 
 private:
        void send(MidiEvent e) const;
-       void parseActions(const Channel& ch, const std::vector<Action>& as) const;
+       void parseActions(ID channelId, const std::vector<Action>& as) const;
 };
 } // namespace giada::m
 
index b009d7b130b14444243a12f8c0c47858afdde9a5..b94e4101a978bd5cab7f1c0f7cf2220caffc3e9b 100644 (file)
@@ -29,7 +29,6 @@
 #include "core/conf.h"
 #include "core/model/model.h"
 #include "utils/math.h"
-#include <cassert>
 
 namespace giada::m
 {
@@ -61,7 +60,7 @@ SampleReactor::SampleReactor(Channel& ch, ID channelId)
 /* -------------------------------------------------------------------------- */
 
 void SampleReactor::react(Channel& ch, const EventDispatcher::Event& e,
-    Sequencer& sequencer, const Conf::Data& conf) const
+    bool chansStopOnSeqHalt, bool canQuantize) const
 {
        if (!ch.hasWave())
                return;
@@ -69,7 +68,7 @@ void SampleReactor::react(Channel& ch, const EventDispatcher::Event& e,
        switch (e.type)
        {
        case EventDispatcher::EventType::KEY_PRESS:
-               press(ch, sequencer, std::get<int>(e.data));
+               press(ch, std::get<int>(e.data), canQuantize);
                break;
 
        case EventDispatcher::EventType::KEY_RELEASE:
@@ -82,7 +81,7 @@ void SampleReactor::react(Channel& ch, const EventDispatcher::Event& e,
                break;
 
        case EventDispatcher::EventType::SEQUENCER_STOP:
-               onStopBySeq(ch, conf.chansStopOnSeqHalt);
+               onStopBySeq(ch, chansStopOnSeqHalt);
                break;
 
        default:
@@ -114,8 +113,8 @@ void SampleReactor::stop(ChannelShared& shared) const
 
 /* -------------------------------------------------------------------------- */
 
-ChannelStatus SampleReactor::pressWhileOff(Channel& ch, Sequencer& sequencer,
-    int velocity, bool isLoop) const
+ChannelStatus SampleReactor::pressWhileOff(Channel& ch, int velocity, bool isLoop,
+    bool canQuantize) const
 {
        if (isLoop)
                return ChannelStatus::WAIT;
@@ -123,7 +122,7 @@ ChannelStatus SampleReactor::pressWhileOff(Channel& ch, Sequencer& sequencer,
        if (ch.samplePlayer->velocityAsVol)
                ch.volume_i = u::math::map(velocity, G_MAX_VELOCITY, G_MAX_VOLUME);
 
-       if (sequencer.canQuantize())
+       if (canQuantize)
        {
                ch.shared->quantizer->trigger(Q_ACTION_PLAY + ch.id);
                return ChannelStatus::OFF;
@@ -134,8 +133,8 @@ ChannelStatus SampleReactor::pressWhileOff(Channel& ch, Sequencer& sequencer,
 
 /* -------------------------------------------------------------------------- */
 
-ChannelStatus SampleReactor::pressWhilePlay(Channel& ch, Sequencer& sequencer,
-    SamplePlayerMode mode, bool isLoop) const
+ChannelStatus SampleReactor::pressWhilePlay(Channel& ch, SamplePlayerMode mode,
+    bool isLoop, bool canQuantize) const
 {
        if (isLoop)
                return ChannelStatus::ENDING;
@@ -143,7 +142,7 @@ ChannelStatus SampleReactor::pressWhilePlay(Channel& ch, Sequencer& sequencer,
        switch (mode)
        {
        case SamplePlayerMode::SINGLE_RETRIG:
-               if (sequencer.canQuantize())
+               if (canQuantize)
                        ch.shared->quantizer->trigger(Q_ACTION_REWIND + ch.id);
                else
                        rewind(*ch.shared, /*localFrame=*/0);
@@ -163,7 +162,7 @@ ChannelStatus SampleReactor::pressWhilePlay(Channel& ch, Sequencer& sequencer,
 
 /* -------------------------------------------------------------------------- */
 
-void SampleReactor::press(Channel& ch, Sequencer& sequencer, int velocity) const
+void SampleReactor::press(Channel& ch, int velocity, bool canQuantize) const
 {
        const SamplePlayerMode mode   = ch.samplePlayer->mode;
        const bool             isLoop = ch.samplePlayer->isAnyLoopMode();
@@ -173,11 +172,11 @@ void SampleReactor::press(Channel& ch, Sequencer& sequencer, int velocity) const
        switch (playStatus)
        {
        case ChannelStatus::OFF:
-               playStatus = pressWhileOff(ch, sequencer, velocity, isLoop);
+               playStatus = pressWhileOff(ch, velocity, isLoop, canQuantize);
                break;
 
        case ChannelStatus::PLAY:
-               playStatus = pressWhilePlay(ch, sequencer, mode, isLoop);
+               playStatus = pressWhilePlay(ch, mode, isLoop, canQuantize);
                break;
 
        case ChannelStatus::WAIT:
index 0915779776d1bca06e610674f477197f3ade81f9..693faf84d7ce47801ea70e79c28a314d69936e09 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "core/conf.h"
 #include "core/eventDispatcher.h"
-#include "core/quantizer.h"
 
 namespace giada::m::model
 {
@@ -40,7 +39,6 @@ namespace giada::m
 {
 class Channel;
 struct ChannelShared;
-class Sequencer;
 
 /* SampleReactor
 Reacts to manual events sent to Sample Channels: key press, key release, 
@@ -57,14 +55,14 @@ public:
 
        SampleReactor(Channel&, ID channelId);
 
-       void react(Channel&, const EventDispatcher::Event&, Sequencer&, const Conf::Data&) const;
+       void react(Channel&, const EventDispatcher::Event&, bool chansStopOnSeqHalt, bool canQuantize) const;
 
 private:
        void          onStopBySeq(Channel&, bool chansStopOnSeqHalt) const;
        void          release(Channel&) const;
-       void          press(Channel&, Sequencer&, int velocity) const;
-       ChannelStatus pressWhilePlay(Channel&, Sequencer&, SamplePlayerMode, bool isLoop) const;
-       ChannelStatus pressWhileOff(Channel&, Sequencer&, int velocity, bool isLoop) const;
+       void          press(Channel&, int velocity, bool canQuantize) const;
+       ChannelStatus pressWhilePlay(Channel&, SamplePlayerMode, bool isLoop, bool canQuantize) const;
+       ChannelStatus pressWhileOff(Channel&, int velocity, bool isLoop, bool canQuantize) const;
        void          rewind(ChannelShared&, Frame localFrame) const;
        void          play(ChannelShared&, Frame localFrame) const;
        void          stop(ChannelShared&) const;
index ed38bf84649ed533af7b5b2b6ecb9b38f7f5b745..462e514d1343496c65ba387e18344be99a06e510 100644 (file)
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/types.h"
-#include "deps/json/single_include/nlohmann/json.hpp"
 #include "utils/fs.h"
 #include "utils/log.h"
 #include <FL/Fl.H>
 #include <cassert>
 #include <fstream>
+#include <nlohmann/json.hpp>
 #include <string>
 
 namespace nl = nlohmann;
@@ -41,20 +41,8 @@ namespace giada::m
 {
 Conf::Conf()
 {
-       /* Initialize m_confFilePath, i.e. the configuration file. In windows it is 
-       in the same dir of the .exe, while in Linux and OS X in ~/.giada */
-
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
-
-       m_confFilePath = u::fs::getHomePath() + G_SLASH + CONF_FILENAME;
-       m_confDirPath  = u::fs::getHomePath() + G_SLASH;
-
-#elif defined(_WIN32)
-
-       m_confFilePath = CONF_FILENAME;
-       m_confDirPath  = "";
-
-#endif
+       m_confFilePath = u::fs::join(u::fs::getHomePath(), CONF_FILENAME);
+       m_confDirPath  = u::fs::getHomePath();
 }
 
 /* -------------------------------------------------------------------------- */
@@ -71,6 +59,7 @@ bool Conf::read()
 
        data.logMode                    = j.value(CONF_KEY_LOG_MODE, data.logMode);
        data.showTooltips               = j.value(CONF_KEY_SHOW_TOOLTIPS, data.showTooltips);
+       data.langMap                    = j.value(CONF_KEY_LANGMAP, data.langMap);
        data.soundSystem                = j.value(CONF_KEY_SOUND_SYSTEM, data.soundSystem);
        data.soundDeviceOut             = j.value(CONF_KEY_SOUND_DEVICE_OUT, data.soundDeviceOut);
        data.soundDeviceIn              = j.value(CONF_KEY_SOUND_DEVICE_IN, data.soundDeviceIn);
@@ -174,6 +163,7 @@ bool Conf::write() const
        j[CONF_KEY_HEADER]                        = "GIADACFG";
        j[CONF_KEY_LOG_MODE]                      = data.logMode;
        j[CONF_KEY_SHOW_TOOLTIPS]                 = data.showTooltips;
+       j[CONF_KEY_LANGMAP]                       = data.langMap;
        j[CONF_KEY_SOUND_SYSTEM]                  = data.soundSystem;
        j[CONF_KEY_SOUND_DEVICE_OUT]              = data.soundDeviceOut;
        j[CONF_KEY_SOUND_DEVICE_IN]               = data.soundDeviceIn;
@@ -246,11 +236,11 @@ bool Conf::write() const
        j[CONF_KEY_REC_TRIGGER_LEVEL]             = data.recTriggerLevel;
        j[CONF_KEY_INPUT_REC_MODE]                = static_cast<int>(data.inputRecMode);
 
-       j[CONF_KEY_BIND_PLAY]           = data.keyBindings.find(KEY_BIND_PLAY)->second;
-       j[CONF_KEY_BIND_REWIND]         = data.keyBindings.find(KEY_BIND_REWIND)->second;
-       j[CONF_KEY_BIND_RECORD_ACTIONS] = data.keyBindings.find(KEY_BIND_RECORD_ACTIONS)->second;
-       j[CONF_KEY_BIND_RECORD_INPUT]   = data.keyBindings.find(KEY_BIND_RECORD_INPUT)->second;
-       j[CONF_KEY_BIND_EXIT]           = data.keyBindings.find(KEY_BIND_EXIT)->second;
+       j[CONF_KEY_BIND_PLAY]           = data.keyBindings[KEY_BIND_PLAY];
+       j[CONF_KEY_BIND_REWIND]         = data.keyBindings[KEY_BIND_REWIND];
+       j[CONF_KEY_BIND_RECORD_ACTIONS] = data.keyBindings[KEY_BIND_RECORD_ACTIONS];
+       j[CONF_KEY_BIND_RECORD_INPUT]   = data.keyBindings[KEY_BIND_RECORD_INPUT];
+       j[CONF_KEY_BIND_EXIT]           = data.keyBindings[KEY_BIND_EXIT];
 
 #ifdef WITH_VST
        j[CONF_KEY_PLUGIN_CHOOSER_X]   = data.pluginChooserX;
index 85418789d6fcc734f84e13b10bcba7052c5178dc..1126f71e234a4d3efcd464b087bac0a1a8bfacf5 100644 (file)
 #include "core/types.h"
 #include "utils/gui.h"
 #include <string>
-#include <unordered_map>
+#include <vector>
 
 namespace giada::m
 {
 class Conf final
 {
 public:
-       using KeyBindings = std::unordered_map<int, int>;
+       using KeyBindings = std::vector<int>;
 
-       static constexpr int KEY_BIND_PLAY           = 1;
-       static constexpr int KEY_BIND_REWIND         = 2;
-       static constexpr int KEY_BIND_RECORD_ACTIONS = 3;
-       static constexpr int KEY_BIND_RECORD_INPUT   = 4;
-       static constexpr int KEY_BIND_EXIT           = 5;
+       static constexpr int KEY_BIND_PLAY           = 0;
+       static constexpr int KEY_BIND_REWIND         = 1;
+       static constexpr int KEY_BIND_RECORD_ACTIONS = 2;
+       static constexpr int KEY_BIND_RECORD_INPUT   = 3;
+       static constexpr int KEY_BIND_EXIT           = 4;
 
        struct Data
        {
-               int  logMode          = LOG_MODE_MUTE;
-               bool showTooltips     = true;
-               int  soundSystem      = G_DEFAULT_SOUNDSYS;
-               int  soundDeviceOut   = G_DEFAULT_SOUNDDEV_OUT;
-               int  soundDeviceIn    = G_DEFAULT_SOUNDDEV_IN;
-               int  channelsOutCount = G_MAX_IO_CHANS;
-               int  channelsOutStart = 0;
-               int  channelsInCount  = 1;
-               int  channelsInStart  = 0;
-               int  samplerate       = G_DEFAULT_SAMPLERATE;
-               int  buffersize       = G_DEFAULT_BUFSIZE;
-               bool limitOutput      = false;
-               int  rsmpQuality      = 0;
+               int         logMode          = LOG_MODE_MUTE;
+               bool        showTooltips     = true;
+               std::string langMap          = "";
+               int         soundSystem      = G_DEFAULT_SOUNDSYS;
+               int         soundDeviceOut   = G_DEFAULT_SOUNDDEV_OUT;
+               int         soundDeviceIn    = G_DEFAULT_SOUNDDEV_IN;
+               int         channelsOutCount = G_MAX_IO_CHANS;
+               int         channelsOutStart = 0;
+               int         channelsInCount  = 1;
+               int         channelsInStart  = 0;
+               int         samplerate       = G_DEFAULT_SAMPLERATE;
+               int         buffersize       = G_DEFAULT_BUFSIZE;
+               bool        limitOutput      = false;
+               int         rsmpQuality      = 0;
 
                int         midiSystem  = 0;
                int         midiPortOut = G_DEFAULT_MIDI_PORT_OUT;
@@ -144,11 +145,12 @@ public:
 #endif
 
                KeyBindings keyBindings = {
-                   {KEY_BIND_PLAY, ' '},
-                   {KEY_BIND_REWIND, FL_BackSpace},
-                   {KEY_BIND_RECORD_ACTIONS, FL_Enter},
-                   {KEY_BIND_RECORD_INPUT, FL_End},
-                   {KEY_BIND_EXIT, FL_Escape}};
+                   ' ',          // KEY_BIND_PLAY
+                   FL_BackSpace, // KEY_BIND_REWIND
+                   FL_Enter,     // KEY_BIND_RECORD_ACTIONS
+                   FL_End,       // KEY_BIND_RECORD_INPUT
+                   FL_Escape     // KEY_BIND_EXIT
+               };
        };
 
        Conf();
index db9bc5bab52d4e2e70962b8835e3452291276b60..97b03438098f59f6b89dcda6a8e392f83502ca7b 100644 (file)
 
 /* -- version --------------------------------------------------------------- */
 constexpr auto G_APP_NAME      = "Giada";
-constexpr auto G_VERSION_STR   = "0.21.0";
+constexpr auto G_VERSION_STR   = "0.22.0";
 constexpr int  G_VERSION_MAJOR = 0;
-constexpr int  G_VERSION_MINOR = 21;
+constexpr int  G_VERSION_MINOR = 22;
 constexpr int  G_VERSION_PATCH = 0;
 
 constexpr auto CONF_FILENAME = "giada.conf";
 
-#ifdef G_OS_WINDOWS
-#define G_SLASH '\\'
-#define G_SLASH_STR "\\"
-#else
-#define G_SLASH '/'
-#define G_SLASH_STR "/"
-#endif
-
 /* -- Engine ---------------------------------------------------------------- */
 /* G_EVENT_DISPATCHER_RATE_MS
 The amount of sleep between each Event Dispatcher cycle. It should be lower
@@ -209,17 +201,12 @@ constexpr int WID_MIDI_INPUT     = -13;
 constexpr int WID_MIDI_OUTPUT    = -14;
 constexpr int WID_MISSING_ASSETS = -15;
 
-/* -- patch signals --------------------------------------------------------- */
-constexpr int G_PATCH_UNSUPPORTED = -2;
-constexpr int G_PATCH_UNREADABLE  = -1;
-constexpr int G_PATCH_INVALID     = 0;
-constexpr int G_PATCH_OK          = 1;
-
-/* -- midimap signals ------------------------------------------------------- */
-constexpr int MIDIMAP_NOT_SPECIFIED = 0x00;
-constexpr int MIDIMAP_UNREADABLE    = 0x01;
-constexpr int MIDIMAP_INVALID       = 0x02;
-constexpr int MIDIMAP_READ_OK       = 0x04;
+/* -- File signals ---------------------------------------------------------- */
+constexpr int G_FILE_NOT_SPECIFIED = -3;
+constexpr int G_FILE_UNSUPPORTED   = -2;
+constexpr int G_FILE_UNREADABLE    = -1;
+constexpr int G_FILE_INVALID       = 0;
+constexpr int G_FILE_OK            = 1;
 
 /* -- MIDI in parameters (for MIDI learning) -------------------------------- */
 constexpr int G_MIDI_IN_ENABLED      = 1;
@@ -367,6 +354,7 @@ constexpr auto G_PATCH_KEY_ACTION_NEXT                = "next";
 constexpr auto CONF_KEY_HEADER                        = "header";
 constexpr auto CONF_KEY_LOG_MODE                      = "log_mode";
 constexpr auto CONF_KEY_SHOW_TOOLTIPS                 = "show_tooltips";
+constexpr auto CONF_KEY_LANGMAP                       = "langmap";
 constexpr auto CONF_KEY_SOUND_SYSTEM                  = "sound_system";
 constexpr auto CONF_KEY_SOUND_DEVICE_IN               = "sound_device_in";
 constexpr auto CONF_KEY_SOUND_DEVICE_OUT              = "sound_device_out";
index 2b05d8f60a1320b7e4dc88a48d06dbd7fb1b29dc..0514011956ccaaa28ac0137f3c0204f606e631ce 100644 (file)
@@ -35,7 +35,7 @@ namespace giada::m
 {
 bool LoadState::isGood() const
 {
-       return patch == G_PATCH_OK && missingWaves.empty() && missingPlugins.empty();
+       return patch == G_FILE_OK && missingWaves.empty() && missingPlugins.empty();
 }
 
 /* -------------------------------------------------------------------------- */
@@ -174,7 +174,7 @@ void Engine::init()
        init::printBuildInfo();
 
        midiMapper.init();
-       if (midiMapper.read(conf.data.midiMapPath) != MIDIMAP_READ_OK)
+       if (midiMapper.read(conf.data.midiMapPath) != G_FILE_OK)
                u::log::print("[Engine::init] MIDI map read failed!\n");
 
        /* Initialize KernelAudio. If fails, interrupt the Engine initialization:
@@ -383,7 +383,7 @@ LoadState Engine::load(const std::string& projectPath, const std::string& patchP
        progress(0.0f);
 
        patch.reset();
-       if (int res = patch.read(patchPath, projectPath); res != G_PATCH_OK)
+       if (int res = patch.read(patchPath, projectPath); res != G_FILE_OK)
                return {res};
 
        progress(0.3f);
@@ -418,7 +418,7 @@ LoadState Engine::load(const std::string& projectPath, const std::string& patchP
 
        progress(1.0f);
 
-       state.patch = G_PATCH_OK;
+       state.patch = G_FILE_OK;
        return state;
 }
 
index c7d242ea927f802fa6ede4dc76748d88cd7d4b98..ed2596d7345c2f4bed2bca43dced68b03491149a 100644 (file)
@@ -55,7 +55,7 @@ struct LoadState
 {
        bool isGood() const;
 
-       int                      patch          = G_PATCH_OK;
+       int                      patch          = G_FILE_OK;
        std::vector<std::string> missingWaves   = {};
        std::vector<std::string> missingPlugins = {};
 };
@@ -97,7 +97,7 @@ public:
 
        /* reset
     Resets all sub-components to the initial state. Useful when Giada needs to
-    be brought back to the starup state. */
+    be brought back to the startup state. */
 
        void reset();
 
index e0c893974dd34d5a9b017c14ba0e6985f49bdf3b..1760a556e0bd039734c7462ff240421c43baeb9c 100644 (file)
@@ -54,7 +54,7 @@ void EventDispatcher::pumpMidiEvent(Event e) { MidiEvents.push(e); }
 
 /* -------------------------------------------------------------------------- */
 
-void EventDispatcher::processFuntions()
+void EventDispatcher::processFunctions()
 {
        assert(onMidiLearn != nullptr);
        assert(onMidiProcess != nullptr);
@@ -105,7 +105,7 @@ void EventDispatcher::process()
        if (m_eventBuffer.size() == 0)
                return;
 
-       processFuntions();
+       processFunctions();
        onProcessChannels(m_eventBuffer);
        onProcessSequencer(m_eventBuffer);
 }
index 34622017a8b5d7e753b2d1001b410d9d3842a289..e506d67dea79a97d09aa911ab7e865850f0b6b5e 100644 (file)
@@ -124,7 +124,7 @@ public:
        std::function<void()>                   onMixerEndOfRecCallback;
 
 private:
-       void processFuntions();
+       void processFunctions();
        void process();
 
        /* m_worker
index ccd97f0b087d08c98678aa84be287dbcef0b434b..b72400cbb774f729855ffc01c242d9a6f9eae165 100644 (file)
@@ -92,6 +92,7 @@ void printBuildInfo()
        u::log::print("[init]   JUCE - %d.%d.%d\n", JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_BUILDNUMBER);
 #endif
        KernelAudio::logCompiledAPIs();
+       KernelMidi::logCompiledAPIs();
 }
 
 /* -------------------------------------------------------------------------- */
@@ -105,8 +106,7 @@ void startup(int argc, char** argv)
        g_ui.init(argc, argv, g_engine);
 
        if (!g_engine.kernelAudio.isReady())
-               v::gdAlert("Your soundcard isn't configured correctly.\n"
-                          "Check the configuration and restart Giada.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_INIT_WRONGSYSTEM));
 }
 
 /* -------------------------------------------------------------------------- */
@@ -121,7 +121,7 @@ int run()
 
 void closeMainWindow()
 {
-       if (!v::gdConfirmWin("Warning", "Quit Giada: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING), g_ui.langMapper.get(v::LangMap::MESSAGE_INIT_QUITGIADA)))
                return;
        shutdown();
 }
index 040b0e2cf1db0fe012030ab1d3d98e0de6a539d1..9d2b119d130a8892943dc4bc455d088e13fb1573 100644 (file)
@@ -244,4 +244,45 @@ void KernelMidi::logPorts(RtMidi& device, std::string name) const
        for (unsigned i = 0; i < device.getPortCount(); i++)
                u::log::print("  %d) %s\n", i, device.getPortName(i));
 }
+
+/* -------------------------------------------------------------------------- */
+
+void KernelMidi::logCompiledAPIs()
+{
+       std::vector<RtMidi::Api> apis;
+       RtMidi::getCompiledApi(apis);
+
+       u::log::print("[KM] Compiled RtMidi APIs: %d\n", apis.size());
+
+       for (const RtMidi::Api& api : apis)
+       {
+               switch (api)
+               {
+               case RtMidi::Api::UNSPECIFIED:
+                       u::log::print("  UNSPECIFIED\n");
+                       break;
+               case RtMidi::Api::MACOSX_CORE:
+                       u::log::print("  CoreAudio\n");
+                       break;
+               case RtMidi::Api::LINUX_ALSA:
+                       u::log::print("  ALSA\n");
+                       break;
+               case RtMidi::Api::UNIX_JACK:
+                       u::log::print("  JACK\n");
+                       break;
+               case RtMidi::Api::WINDOWS_MM:
+                       u::log::print("  Microsoft Multimedia MIDI API\n");
+                       break;
+               case RtMidi::Api::RTMIDI_DUMMY:
+                       u::log::print("  Dummy\n");
+                       break;
+               case RtMidi::Api::WEB_MIDI_API:
+                       u::log::print("  Web MIDI API\n");
+                       break;
+               default:
+                       u::log::print("  (unknown)\n");
+                       break;
+               }
+       }
+}
 } // namespace giada::m
index ac10e22f907d432dba048f3dac2d4117a0541623..93fe8ccac0e0bfd8581f4b61fad04f8589ca18bf 100644 (file)
@@ -41,6 +41,8 @@ class KernelMidi final
 public:
        KernelMidi();
 
+       static void logCompiledAPIs();
+
        unsigned countOutPorts() const;
        unsigned countInPorts() const;
 
index 2cff6997c259b549c5bc847ed20983548fcd2d9f..843fd15b0edeec00405fda3c247c18111e04ebe4 100644 (file)
@@ -116,7 +116,7 @@ void MidiDispatcher::dispatch(uint32_t msg)
 
        /* Start dispatcher. Don't parse channels if MIDI learn is ON, just learn 
        the incoming MIDI signal. The action is not invoked directly, but scheduled 
-       to be perfomed by the Event Dispatcher. */
+       to be performed by the Event Dispatcher. */
 
        Action action = {0, 0, 0, midiEvent};
        auto   event  = m_learnCb != nullptr ? EventDispatcher::EventType::MIDI_DISPATCHER_LEARN : EventDispatcher::EventType::MIDI_DISPATCHER_PROCESS;
index 839d69d12ac2163008e57aed04a626c941e66fbc..1adfac5582537a1add408abe1d1793ec86464fe3 100644 (file)
@@ -58,14 +58,7 @@ template <typename KernelMidiI>
 MidiMapper<KernelMidiI>::MidiMapper(KernelMidiI& k)
 : m_kernelMidi(k)
 {
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <typename KernelMidiI>
-const std::vector<std::string>& MidiMapper<KernelMidiI>::getMapFilesFound() const
-{
-       return m_mapFiles;
+       m_mapsPath = u::fs::getMidiMapsPath();
 }
 
 /* -------------------------------------------------------------------------- */
@@ -73,28 +66,7 @@ const std::vector<std::string>& MidiMapper<KernelMidiI>::getMapFilesFound() cons
 template <typename KernelMidiI>
 void MidiMapper<KernelMidiI>::init()
 {
-       m_mapsPath = u::fs::getHomePath() + G_SLASH + "midimaps" + G_SLASH;
-
-       /* scan dir of midi maps and load the filenames into m_mapFiles vector. */
-
-       u::log::print("[MidiMapper::init] scanning midimaps directory '%s'...\n",
-           m_mapsPath);
-
-       if (!std::filesystem::exists(m_mapsPath))
-       {
-               u::log::print("[MidiMapper::init] unable to scan midimaps directory!\n");
-               return;
-       }
-
-       for (const auto& d : std::filesystem::directory_iterator(m_mapsPath))
-       {
-               // TODO - check if is a valid midiMap file (verify headers)
-               if (!d.is_regular_file())
-                       continue;
-               u::log::print("[MidiMapper::init] found midiMap '%s'\n", d.path().filename().string());
-               m_mapFiles.push_back(d.path().filename().string());
-       }
-
+       Mapper::init();
        u::log::print("[MidiMapper::init] total midimaps found: %d\n", m_mapFiles.size());
 }
 
@@ -103,25 +75,17 @@ void MidiMapper<KernelMidiI>::init()
 template <typename KernelMidiI>
 int MidiMapper<KernelMidiI>::read(const std::string& file)
 {
-       if (file.empty())
-       {
-               u::log::print("[MidiMapper::read] midiMap not specified, nothing to do\n");
-               return MIDIMAP_NOT_SPECIFIED;
-       }
-
-       u::log::print("[MidiMapper::read] reading midiMap file '%s'\n", file);
-
-       std::ifstream ifs(m_mapsPath + file);
-       if (!ifs.good())
-               return MIDIMAP_UNREADABLE;
+       std::optional<nl::json> res = Mapper::read(file);
+       if (!res)
+               return G_FILE_UNREADABLE;
 
-       nl::json j = nl::json::parse(ifs);
+       nl::json j = res.value();
 
        currentMap.brand  = j[MIDIMAP_KEY_BRAND];
        currentMap.device = j[MIDIMAP_KEY_DEVICE];
 
        if (!readInitCommands(currentMap, j))
-               return MIDIMAP_UNREADABLE;
+               return G_FILE_UNREADABLE;
        if (readCommand(j, currentMap.muteOn, MIDIMAP_KEY_MUTE_ON))
                parse(currentMap.muteOn);
        if (readCommand(j, currentMap.muteOff, MIDIMAP_KEY_MUTE_OFF))
@@ -141,7 +105,7 @@ int MidiMapper<KernelMidiI>::read(const std::string& file)
        if (readCommand(j, currentMap.playingInaudible, MIDIMAP_KEY_PLAYING_INAUDIBLE))
                parse(currentMap.playingInaudible);
 
-       return MIDIMAP_READ_OK;
+       return G_FILE_OK;
 }
 
 /* -------------------------------------------------------------------------- */
index f8f2c13f2e2f6c48a8fc364f61b1b7246887abe3..8bcd89028e8ce4cbc17ca807fd328203e486750f 100644 (file)
@@ -27,7 +27,8 @@
 #ifndef G_MIDIMAPPER_H
 #define G_MIDIMAPPER_H
 
-#include "deps/json/single_include/nlohmann/json.hpp"
+#include "mapper.h"
+#include <nlohmann/json.hpp>
 #include <string>
 #include <vector>
 
@@ -70,17 +71,14 @@ struct MidiMap
        Message              playingInaudible;
 };
 
+/* -------------------------------------------------------------------------- */
+
 template <typename KernelMidiI>
-class MidiMapper final
+class MidiMapper final : public Mapper
 {
 public:
        MidiMapper(KernelMidiI&);
 
-       /* getMapFilesFound
-       Returns a reference to the list of midimaps found. */
-
-       const std::vector<std::string>& getMapFilesFound() const;
-
        /* init
        Parses the midimap folders and find the available midimaps. */
 
@@ -126,17 +124,6 @@ private:
 
        /* TODO - don't edit message in place! */
        bool readCommand(const nlohmann::json& j, MidiMap::Message& m, const std::string& key) const;
-
-       /* m_mapsPath
-       Path to folder containing midimap files, different between OSes. */
-
-       std::string m_mapsPath;
-
-       /* m_mapFiles
-       The available .giadamap files. Each element of the vector represents 
-       a .giadamap file found in the midimap folder. */
-
-       std::vector<std::string> m_mapFiles;
 };
 
 extern template class MidiMapper<KernelMidi>;
index 498b12fbb320d04e5733dcbdaa831b53c150dfe5..bfeb64c23cb9de36b96f9cf318767292905a02e1 100644 (file)
 
 #include "patch.h"
 #include "core/mixer.h"
-#include "deps/json/single_include/nlohmann/json.hpp"
 #include "utils/log.h"
 #include "utils/math.h"
 #include <fstream>
+#include <nlohmann/json.hpp>
 
 namespace nl = nlohmann;
 
@@ -107,7 +107,7 @@ void readWaves_(Patch::Data& patch, const nl::json& j, const std::string& basePa
        {
                Patch::Wave w;
                w.id   = jwave.value(PATCH_KEY_WAVE_ID, ++id);
-               w.path = basePath + G_SLASH + jwave.value(PATCH_KEY_WAVE_PATH, "");
+               w.path = u::fs::join(basePath, jwave.value(PATCH_KEY_WAVE_PATH, ""));
                patch.waves.push_back(w);
        }
 }
@@ -439,19 +439,19 @@ int Patch::read(const std::string& file, const std::string& basePath)
 {
        std::ifstream ifs(file);
        if (!ifs.good())
-               return G_PATCH_UNREADABLE;
+               return G_FILE_UNREADABLE;
 
        nl::json j = nl::json::parse(ifs);
 
        if (j[PATCH_KEY_HEADER] != "GIADAPTC")
-               return G_PATCH_INVALID;
+               return G_FILE_INVALID;
 
        data.version = {
            static_cast<int>(j[PATCH_KEY_VERSION_MAJOR]),
            static_cast<int>(j[PATCH_KEY_VERSION_MINOR]),
            static_cast<int>(j[PATCH_KEY_VERSION_PATCH])};
        if (data.version < Version{0, 16, 0})
-               return G_PATCH_UNSUPPORTED;
+               return G_FILE_UNSUPPORTED;
 
        try
        {
@@ -468,9 +468,9 @@ int Patch::read(const std::string& file, const std::string& basePath)
        catch (nl::json::exception& e)
        {
                u::log::print("[patch::read] Exception thrown: %s\n", e.what());
-               return G_PATCH_INVALID;
+               return G_FILE_INVALID;
        }
 
-       return G_PATCH_OK;
+       return G_FILE_OK;
 }
 } // namespace giada::m
index 8ffbf6e3b7b882cda4c2441f613730a015737cb4..ce874dd3ba3a7dd39f72f5f30bdfc96e1fd5bdf6 100644 (file)
@@ -49,7 +49,7 @@ void PluginManager::reset(SortMethod sortMethod)
        if (m_formatManager.getNumFormats() == 0) // Must be called only once
                m_formatManager.addDefaultFormats();
 
-       loadList(u::fs::getHomePath() + G_SLASH + "plugins.xml");
+       loadList(u::fs::join(u::fs::getHomePath(), "plugins.xml"));
        sortPlugins(sortMethod);
 }
 
index fbb16bb055e549154aa51a558e4897ac99589d59..fb8cec7a2d0259d970528b7c16b9b2dd0454bb5c 100644 (file)
@@ -65,7 +65,7 @@ int getBits_(const SF_INFO& header)
 
 std::string makeWavePath_(const std::string& base, const m::Wave& w, int k)
 {
-       return base + G_SLASH + w.getBasename(/*ext=*/false) + "-" + std::to_string(k) + w.getExtension();
+       return u::fs::join(base, w.getBasename(/*ext=*/false) + "-" + std::to_string(k) + w.getExtension());
 }
 
 /* -------------------------------------------------------------------------- */
@@ -88,7 +88,7 @@ bool isWavePathUnique_(const m::Wave& skip, const std::string& path,
 std::string makeUniqueWavePath(const std::string& base, const m::Wave& w,
     const std::vector<std::unique_ptr<Wave>>& waves)
 {
-       std::string path = base + G_SLASH + w.getBasename(/*ext=*/true);
+       std::string path = u::fs::join(base, w.getBasename(/*ext=*/true));
        if (isWavePathUnique_(w, path, waves))
                return path;
 
index 2e25bc26b3fcd1644f4d9e1fd94062381379eac6..064434250b74409c193c9b9e33bb1ec564d97e85 100644 (file)
@@ -51,7 +51,6 @@
 #include "gui/elems/mainWindow/keyboard/channelButton.h"
 #include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/keyboard/sampleChannel.h"
-#include "gui/elems/sampleEditor/boostTool.h"
 #include "gui/elems/sampleEditor/panTool.h"
 #include "gui/elems/sampleEditor/pitchTool.h"
 #include "gui/elems/sampleEditor/rangeTool.h"
@@ -78,13 +77,13 @@ namespace
 void printLoadError_(int res)
 {
        if (res == G_RES_ERR_WRONG_DATA)
-               v::gdAlert("Multichannel samples not supported.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_MULTICHANNOTSUPPORTED));
        else if (res == G_RES_ERR_IO)
-               v::gdAlert("Unable to read this sample.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_CANTREADSAMPLE));
        else if (res == G_RES_ERR_PATH_TOO_LONG)
-               v::gdAlert("File path too long.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_PATHTOOLONG));
        else if (res == G_RES_ERR_NO_DATA)
-               v::gdAlert("No file specified.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_NOFILESPECIFIED));
 }
 } // namespace
 
@@ -176,7 +175,7 @@ std::vector<Data> getChannels()
 
 int loadChannel(ID channelId, const std::string& fname)
 {
-       auto progress = g_ui.mainWindow->getScopedProgress("Loading sample...");
+       auto progress = g_ui.mainWindow->getScopedProgress(g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_LOADINGSAMPLES));
 
        m::WaveManager::Result res = g_engine.waveManager.createFromFile(fname, /*id=*/0,
            g_engine.kernelAudio.getSampleRate(), g_engine.conf.data.rsmpQuality);
@@ -213,7 +212,7 @@ void addChannel(ID columnId, ChannelType type)
 
 void addAndLoadChannels(ID columnId, const std::vector<std::string>& fnames)
 {
-       auto progress = g_ui.mainWindow->getScopedProgress("Loading samples...");
+       auto progress = g_ui.mainWindow->getScopedProgress(g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_LOADINGSAMPLES));
 
        bool errors = false;
        int  i      = 0;
@@ -231,14 +230,14 @@ void addAndLoadChannels(ID columnId, const std::vector<std::string>& fnames)
        }
 
        if (errors)
-               v::gdAlert("Some files weren't loaded successfully.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_LOADINGSAMPLESERROR));
 }
 
 /* -------------------------------------------------------------------------- */
 
 void deleteChannel(ID channelId)
 {
-       if (!v::gdConfirmWin("Warning", "Delete channel: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING), g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_DELETE)))
                return;
        g_ui.closeAllSubwindows();
 
@@ -256,7 +255,7 @@ void deleteChannel(ID channelId)
 
 void freeChannel(ID channelId)
 {
-       if (!v::gdConfirmWin("Warning", "Free channel: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING), g_ui.langMapper.get(v::LangMap::MESSAGE_CHANNEL_FREE)))
                return;
        g_ui.closeAllSubwindows();
        g_engine.actionRecorder.clearChannel(channelId);
index db2c926d66e48169dd0c8e45681783f8638d77c9..258e3a9ccfc4835432a2df8a9a8e7aae76c59ac7 100644 (file)
@@ -243,6 +243,8 @@ MiscData getMiscData()
        MiscData miscData;
        miscData.logMode      = g_engine.conf.data.logMode;
        miscData.showTooltips = g_engine.conf.data.showTooltips;
+       miscData.langMaps     = g_ui.langMapper.getMapFilesFound();
+       miscData.langMap      = g_engine.conf.data.langMap;
        return miscData;
 }
 /* -------------------------------------------------------------------------- */
@@ -293,7 +295,8 @@ void save(const MiscData& data)
 {
        g_engine.conf.data.logMode      = data.logMode;
        g_engine.conf.data.showTooltips = data.showTooltips;
-       Fl_Tooltip::enable(g_engine.conf.data.showTooltips);
+       g_engine.conf.data.langMap      = data.langMap;
+       Fl_Tooltip::enable(g_engine.conf.data.showTooltips); // TODO - move this to UI init
 }
 
 /* -------------------------------------------------------------------------- */
@@ -303,7 +306,7 @@ void save(const MiscData& data)
 void scanPlugins(std::string dir, const std::function<void(float)>& progress)
 {
        g_engine.pluginManager.scanDirs(dir, progress);
-       g_engine.pluginManager.saveList(u::fs::getHomePath() + G_SLASH + "plugins.xml");
+       g_engine.pluginManager.saveList(u::fs::join(u::fs::getHomePath(), "plugins.xml"));
 }
 
 /* -------------------------------------------------------------------------- */
@@ -315,7 +318,7 @@ void setPluginPathCb(void* data)
 
        if (browser->getCurrentPath() == "")
        {
-               v::gdAlert("Invalid path.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::CONFIG_PLUGINS_INVALIDPATH));
                return;
        }
 
index 55878c627c72bdf5630c200799342e5c6d5c1d01..fa9105f0071d12b063f6b6a58e4d7fc214ae1332 100644 (file)
@@ -108,8 +108,13 @@ struct PluginData
 
 struct MiscData
 {
-       int  logMode;
-       bool showTooltips;
+       int                      logMode;
+       bool                     showTooltips;
+       std::vector<std::string> langMaps;
+
+       /* Selectable values. */
+
+       std::string langMap;
 };
 
 /* get*
index 30e2d4fbef87b9d66cf124240c5655207fef02ad..d7c1a50c668947fe07152269c48e78059e551f19 100644 (file)
@@ -72,8 +72,8 @@ bool isValidKey_(int key)
 {
        if (strlen(Fl::event_text()) == 0)
                return false;
-       for (const auto& [_, val] : g_engine.conf.data.keyBindings)
-               if (key == val)
+       for (const int& bind : g_engine.conf.data.keyBindings)
+               if (key == bind)
                        return false;
        return true;
 }
index 76e73578fd5b7df35fd2db4b5c932ee4bc61b32a..f611a0f1dc7452649c6debcb8583adcc783fa173 100644 (file)
@@ -62,8 +62,8 @@ namespace giada::c::layout
 {
 void openBrowserForProjectLoad()
 {
-       v::gdWindow* childWin = new v::gdBrowserLoad("Open project", g_engine.conf.data.patchPath,
-           c::storage::loadProject, 0, g_engine.conf.data);
+       v::gdWindow* childWin = new v::gdBrowserLoad(g_ui.langMapper.get(v::LangMap::BROWSER_OPENPROJECT),
+           g_engine.conf.data.patchPath, c::storage::loadProject, 0, g_engine.conf.data);
        g_ui.openSubWindow(*g_ui.mainWindow.get(), childWin, WID_FILE_BROWSER);
 }
 
@@ -71,8 +71,8 @@ void openBrowserForProjectLoad()
 
 void openBrowserForProjectSave()
 {
-       v::gdWindow* childWin = new v::gdBrowserSave("Save project", g_engine.conf.data.patchPath,
-           g_engine.patch.data.name, c::storage::saveProject, 0, g_engine.conf.data);
+       v::gdWindow* childWin = new v::gdBrowserSave(g_ui.langMapper.get(v::LangMap::BROWSER_SAVEPROJECT),
+           g_engine.conf.data.patchPath, g_engine.patch.data.name, c::storage::saveProject, 0, g_engine.conf.data);
        g_ui.openSubWindow(*g_ui.mainWindow.get(), childWin, WID_FILE_BROWSER);
 }
 
@@ -80,7 +80,7 @@ void openBrowserForProjectSave()
 
 void openBrowserForSampleLoad(ID channelId)
 {
-       v::gdWindow* w = new v::gdBrowserLoad("Browse sample",
+       v::gdWindow* w = new v::gdBrowserLoad(g_ui.langMapper.get(v::LangMap::BROWSER_OPENSAMPLE),
            g_engine.conf.data.samplePath.c_str(), c::storage::loadSample, channelId, g_engine.conf.data);
        g_ui.openSubWindow(*g_ui.mainWindow.get(), w, WID_FILE_BROWSER);
 }
@@ -89,7 +89,7 @@ void openBrowserForSampleLoad(ID channelId)
 
 void openBrowserForSampleSave(ID channelId)
 {
-       v::gdWindow* w = new v::gdBrowserSave("Save sample",
+       v::gdWindow* w = new v::gdBrowserSave(g_ui.langMapper.get(v::LangMap::BROWSER_SAVESAMPLE),
            g_engine.conf.data.samplePath.c_str(), "", c::storage::saveSample, channelId, g_engine.conf.data);
        g_ui.openSubWindow(*g_ui.mainWindow.get(), w, WID_FILE_BROWSER);
 }
@@ -209,7 +209,7 @@ void openMissingAssetsWindow(const m::LoadState& state)
 
 void openBrowserForPlugins(v::gdWindow& parent)
 {
-       v::gdBrowserDir* browser = new v::gdBrowserDir("Add plug-ins directory",
+       v::gdBrowserDir* browser = new v::gdBrowserDir(g_ui.langMapper.get(v::LangMap::BROWSER_OPENPLUGINSDIR),
            g_engine.conf.data.patchPath, c::config::setPluginPathCb, g_engine.conf.data);
        parent.addSubWindow(browser);
 }
index dca6339e53d7293c156027eaa53626671d4aa263..320ebf29262cf29a2fedb1cdfc018ffe7381de13 100644 (file)
@@ -213,7 +213,8 @@ void quantize(int val)
 
 void clearAllSamples()
 {
-       if (!v::gdConfirmWin("Warning", "Free all Sample channels: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING),
+               g_ui.langMapper.get(v::LangMap::MESSAGE_MAIN_FREEALLSAMPLES)))
                return;
        g_ui.closeSubWindow(WID_SAMPLE_EDITOR);
        g_engine.sequencer.setStatus(SeqStatus::STOPPED);
@@ -226,7 +227,8 @@ void clearAllSamples()
 
 void clearAllActions()
 {
-       if (!v::gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING),
+               g_ui.langMapper.get(v::LangMap::MESSAGE_MAIN_CLEARALLACTIONS)))
                return;
        g_ui.closeSubWindow(WID_ACTION_EDITOR);
        g_engine.actionRecorder.clearAllActions();
@@ -276,7 +278,8 @@ void printDebugInfo()
 
 void closeProject()
 {
-       if (!v::gdConfirmWin("Warning", "Close project: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING),
+               g_ui.langMapper.get(v::LangMap::MESSAGE_MAIN_CLOSEPROJECT)))
                return;
        g_engine.mixer.disable();
        g_ui.reset();
index a25f38218db5a3ad9b48a44c55f016e423dc6e5c..326f1aa45b4b002c3bf9b302e51d970369cd4d93 100644 (file)
@@ -50,7 +50,8 @@ namespace giada::c::recorder
 {
 void clearAllActions(ID channelId)
 {
-       if (!v::gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING),
+               g_ui.langMapper.get(v::LangMap::MESSAGE_MAIN_CLEARALLACTIONS)))
                return;
        g_engine.actionRecorder.clearChannel(channelId);
        updateChannel(channelId, /*updateActionEditor=*/true);
@@ -60,7 +61,8 @@ void clearAllActions(ID channelId)
 
 void clearVolumeActions(ID channelId)
 {
-       if (!v::gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING),
+               g_ui.langMapper.get(v::LangMap::MESSAGE_MAIN_CLEARALLVOLUMEACTIONS)))
                return;
        g_engine.actionRecorder.clearActions(channelId, m::MidiEvent::ENVELOPE);
        updateChannel(channelId, /*updateActionEditor=*/true);
@@ -70,7 +72,8 @@ void clearVolumeActions(ID channelId)
 
 void clearStartStopActions(ID channelId)
 {
-       if (!v::gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING),
+               g_ui.langMapper.get(v::LangMap::MESSAGE_MAIN_CLEARALLSTARTSTOPACTIONS)))
                return;
        g_engine.actionRecorder.clearActions(channelId, m::MidiEvent::NOTE_ON);
        g_engine.actionRecorder.clearActions(channelId, m::MidiEvent::NOTE_OFF);
index 942fb9ecd35d92f9063ee1b16ab9a56bb96fd0c5..e3545e2af3c37a840a94fa5116bc15ce7c0d8263 100644 (file)
@@ -40,7 +40,6 @@
 #include "gui/elems/basics/button.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
 #include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "gui/elems/sampleEditor/boostTool.h"
 #include "gui/elems/sampleEditor/panTool.h"
 #include "gui/elems/sampleEditor/pitchTool.h"
 #include "gui/elems/sampleEditor/rangeTool.h"
@@ -372,7 +371,7 @@ bool isWaveBufferFull()
 
 void reload(ID channelId)
 {
-       if (!v::gdConfirmWin("Warning", "Reload sample: are you sure?"))
+       if (!v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING), "Reload sample: are you sure?"))
                return;
 
        if (channel::loadChannel(channelId, getWave_(channelId).getPath()) != G_RES_OK)
index 8a7ab66b38f513033e82ed8e7b70a37b348ddd59..cb3c6aa2f34946bad7675c7e35c1a5ccc3817b2d 100644 (file)
@@ -67,9 +67,9 @@ void loadProject(void* data)
        v::gdBrowserLoad* browser = static_cast<v::gdBrowserLoad*>(data);
 
        const std::string projectPath = browser->getSelectedItem();
-       const std::string patchPath   = projectPath + G_SLASH + u::fs::stripExt(u::fs::basename(projectPath)) + ".gptc";
+       const std::string patchPath   = u::fs::join(projectPath, u::fs::stripExt(u::fs::basename(projectPath)) + ".gptc");
 
-       auto progress   = g_ui.mainWindow->getScopedProgress("Loading project...");
+       auto progress   = g_ui.mainWindow->getScopedProgress(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_LOADINGPROJECT));
        auto progressCb = [&p = progress.get()](float v) {
                p.setProgress(v);
        };
@@ -81,14 +81,14 @@ void loadProject(void* data)
 
        m::LoadState state = g_engine.load(projectPath, patchPath, progressCb);
 
-       if (state.patch != G_PATCH_OK)
+       if (state.patch != G_FILE_OK)
        {
-               if (state.patch == G_PATCH_UNREADABLE)
-                       v::gdAlert("This patch is unreadable.");
-               else if (state.patch == G_PATCH_INVALID)
-                       v::gdAlert("This patch is not valid.");
-               else if (state.patch == G_PATCH_UNSUPPORTED)
-                       v::gdAlert("This patch format is no longer supported.");
+               if (state.patch == G_FILE_UNREADABLE)
+                       v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_PATCHUNREADABLE));
+               else if (state.patch == G_FILE_INVALID)
+                       v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_PATCHINVALID));
+               else if (state.patch == G_FILE_UNSUPPORTED)
+                       v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_PATCHUNSUPPORTED));
                return;
        }
 
@@ -109,19 +109,20 @@ void saveProject(void* data)
        v::gdBrowserSave* browser = static_cast<v::gdBrowserSave*>(data);
 
        const std::string projectName = u::fs::stripExt(browser->getName());
-       const std::string projectPath = browser->getCurrentPath() + G_SLASH + projectName + ".gprj";
-       const std::string patchPath   = projectPath + G_SLASH + projectName + ".gptc";
+       const std::string projectPath = u::fs::join(browser->getCurrentPath(), projectName + ".gprj");
+       const std::string patchPath   = u::fs::join(projectPath, projectName + ".gptc");
 
        if (projectName == "")
        {
-               v::gdAlert("Please choose a project name.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_CHOOSEPROJECTNAME));
                return;
        }
 
-       if (u::fs::dirExists(projectPath) && !v::gdConfirmWin("Warning", "Project exists: overwrite?"))
+       if (u::fs::dirExists(projectPath) &&
+           !v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING), g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_PROJECTEXISTS)))
                return;
 
-       auto progress   = g_ui.mainWindow->getScopedProgress("Saving project...");
+       auto progress   = g_ui.mainWindow->getScopedProgress(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_SAVINGPROJECT));
        auto progressCb = [&p = progress.get()](float v) {
                p.setProgress(v);
        };
@@ -130,7 +131,7 @@ void saveProject(void* data)
 
        if (!g_engine.store(projectName, projectPath, patchPath, progressCb))
        {
-               v::gdAlert("Unable to save the project!");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_SAVINGPROJECTERROR));
                return;
        }
 
@@ -147,7 +148,7 @@ void loadSample(void* data)
        if (fullPath.empty())
                return;
 
-       auto progress = g_ui.mainWindow->getScopedProgress("Loading sample...");
+       auto progress = g_ui.mainWindow->getScopedProgress(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_LOADINGSAMPLE));
 
        if (int res = c::channel::loadChannel(browser->getChannelId(), fullPath); res == G_RES_OK)
        {
@@ -168,13 +169,15 @@ void saveSample(void* data)
 
        if (name == "")
        {
-               v::gdAlert("Please choose a file name.");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_CHOOSEFILENAME));
                return;
        }
 
-       std::string filePath = folderPath + G_SLASH + u::fs::stripExt(name) + ".wav";
+       std::string filePath = u::fs::join(folderPath, u::fs::stripExt(name) + ".wav");
 
-       if (u::fs::fileExists(filePath) && !v::gdConfirmWin("Warning", "File exists: overwrite?"))
+       if (u::fs::fileExists(filePath) &&
+           !v::gdConfirmWin(g_ui.langMapper.get(v::LangMap::COMMON_WARNING),
+               g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_FILEEXISTS)))
                return;
 
        ID       waveId = g_engine.model.get().getChannel(channelId).samplePlayer->getWaveId();
@@ -184,7 +187,7 @@ void saveSample(void* data)
 
        if (!g_engine.waveManager.save(*wave, filePath))
        {
-               v::gdAlert("Unable to save this sample!");
+               v::gdAlert(g_ui.langMapper.get(v::LangMap::MESSAGE_STORAGE_SAVINGFILEERROR));
                return;
        }
 
index ac3ded7e6c8ea8b79eba0ea320a5aff0aab61c8f..9635c79729ad6d42892f2e1eae22881eab382741 100644 (file)
 #ifdef WITH_VST
 #include "deps/juce-config.h"
 #endif
-#include "about.h"
+#include "gui/dialogs/about.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/flex.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
+#include <fmt/core.h>
+
+extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
 gdAbout::gdAbout()
 #ifdef WITH_VST
-: gdWindow(340, 415, "About Giada")
+: gdWindow(340, 415, g_ui.langMapper.get(LangMap::ABOUT_TITLE))
 #else
-: gdWindow(340, 330, "About Giada")
-#endif
-, logo(8, 20, 324, 86)
-, text(8, 120, 324, 140)
-, close(252, h() - 28, 80, 20, "Close")
-#ifdef WITH_VST
-, vstText(8, 315, 324, 46)
-, vstLogo(8, 265, 324, 50)
+: gdWindow(340, 330, g_ui.langMapper.get(LangMap::ABOUT_TITLE))
 #endif
 {
-       set_modal();
-
-       std::string version = G_VERSION_STR;
 #ifdef G_DEBUG_MODE
-       version += " (debug build)";
+       constexpr bool debug = true;
+#else
+       constexpr bool debug = false;
 #endif
 
-       logo.image(new Fl_Pixmap(giada_logo_xpm));
-       text.align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
-       text.copy_label(std::string(
-           "Version " + version + " (" BUILD_DATE ")\n\n"
-                                  "Developed by Monocasual Laboratories\n\n"
-                                  "Released under the terms of the GNU General\n"
-                                  "Public License (GPL v3)\n\n"
-                                  "News, infos, contacts and documentation:\n"
-                                  "www.giadamusic.com")
-                           .c_str());
+       geFlex* container = new geFlex(getContentBounds().reduced({G_GUI_OUTER_MARGIN}), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
+       {
+               geFlex* body = new geFlex(Direction::VERTICAL);
+               {
+                       geBox* logo = new geBox();
+                       logo->image(new Fl_Pixmap(giada_logo_xpm));
 
-       add(logo);
-       add(text);
-       add(close);
+                       geBox* text = new geBox();
+                       text->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
+                       text->copy_label(fmt::format(g_ui.langMapper.get(LangMap::ABOUT_BODY),
+                           G_VERSION_STR, debug ? "Debug" : "Release", BUILD_DATE)
+                                            .c_str());
 
 #ifdef WITH_VST
+                       geBox* vstLogo = new geBox();
+                       vstLogo->image(new Fl_Pixmap(vstLogo_xpm));
+                       vstLogo->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
 
-       vstLogo.image(new Fl_Pixmap(vstLogo_xpm));
-       vstLogo.position(vstLogo.x(), text.y() + text.h() + 8);
-       vstText.label(
-           "VST Plug-In Technology by Steinberg\n"
-           "VST is a trademark of Steinberg\nMedia Technologies GmbH");
-       vstText.position(vstText.x(), vstLogo.y() + vstLogo.h());
-
-       add(vstLogo);
-       add(vstText);
-
+                       geBox* vstText = new geBox();
+                       vstText->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
+                       vstText->label(g_ui.langMapper.get(LangMap::ABOUT_BODY_VST));
 #endif
 
-       close.callback(cb_close, (void*)this);
-       u::gui::setFavicon(this);
-       setId(WID_ABOUT);
-       show();
-}
+                       body->add(logo, 120);
+                       body->add(text, 140);
+#ifdef WITH_VST
+                       body->add(vstLogo, 60);
+                       body->add(vstText);
+#endif
+                       body->end();
+               }
 
-/* -------------------------------------------------------------------------- */
+               geFlex* footer = new geFlex(Direction::HORIZONTAL);
+               {
+                       geButton* close = new geButton(g_ui.langMapper.get(LangMap::COMMON_CLOSE));
+                       close->onClick  = [this]() { do_callback(); };
+                       footer->add(new geBox()); // Spacer
+                       footer->add(close, 80);
+                       footer->end();
+               }
 
-void gdAbout::cb_close(Fl_Widget* /*w*/, void* p) { ((gdAbout*)p)->cb_close(); }
+               container->add(body);
+               container->add(footer, G_GUI_UNIT);
+               container->end();
+       }
 
-/* -------------------------------------------------------------------------- */
+       add(container);
 
-void gdAbout::cb_close()
-{
-       do_callback();
+       set_modal();
+       u::gui::setFavicon(this);
+       setId(WID_ABOUT);
+       show();
 }
 } // namespace giada::v
\ No newline at end of file
index 7083d6d455ef5c7886f9772df25651fc2614f371..0a9394dd6d057d89a6ba2b2bc02f728b70a83b09 100644 (file)
@@ -28,8 +28,6 @@
 #define GD_ABOUT_H
 
 #include "gui/dialogs/window.h"
-#include "gui/elems/basics/box.h"
-#include "gui/elems/basics/button.h"
 
 namespace giada::v
 {
@@ -37,18 +35,6 @@ class gdAbout : public gdWindow
 {
 public:
        gdAbout();
-
-       static void cb_close(Fl_Widget* /*w*/, void* p);
-       inline void cb_close();
-
-private:
-       geBox    logo;
-       geBox    text;
-       geButton close;
-#ifdef WITH_VST
-       geBox vstText;
-       geBox vstLogo;
-#endif
 };
 } // namespace giada::v
 
index 18c9051177a4c027be337213388258460c66bea7..f92529a0d73a70e86e46e483b72591a8930e2c69 100644 (file)
@@ -34,6 +34,7 @@
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
 #include "gui/elems/basics/scrollPack.h"
+#include "gui/ui.h"
 #include "src/core/actions/action.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <limits>
 #include <string>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdBaseActionEditor::gdBaseActionEditor(ID channelId, m::Conf::Data& conf)
-: gdWindow(conf.actionEditorX, conf.actionEditorY, conf.actionEditorW, conf.actionEditorH)
+: gdWindow(conf.actionEditorX, conf.actionEditorY, conf.actionEditorW, conf.actionEditorH, g_ui.langMapper.get(LangMap::ACTIONEDITOR_TITLE))
 , channelId(channelId)
 , gridTool(0, 0, conf)
 , zoomInBtn(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm)
@@ -67,9 +70,9 @@ gdBaseActionEditor::gdBaseActionEditor(ID channelId, m::Conf::Data& conf)
            h() - (G_GUI_OUTER_MARGIN * 3) - 20);
 
        zoomInBtn.callback(cb_zoomIn, this);
-       zoomInBtn.copy_tooltip("Zoom in");
+       zoomInBtn.copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_ZOOMIN));
        zoomOutBtn.callback(cb_zoomOut, this);
-       zoomOutBtn.copy_tooltip("Zoom out");
+       zoomOutBtn.copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_ZOOMOUT));
 
        add(m_barTop);
        add(m_splitScroll);
@@ -142,15 +145,8 @@ void gdBaseActionEditor::zoomOut()
 void gdBaseActionEditor::prepareWindow()
 {
        u::gui::setFavicon(this);
-
-       std::string l = "Action Editor";
-       if (m_data.channelName != "")
-               l += " - " + m_data.channelName;
-       copy_label(l.c_str());
-
        set_non_modal();
        size_range(640, 284);
-
        show();
 }
 
index 944d4c4dc2e107fdea96ef2f62009bfee6290f36..a42c25e17b18397e2ada1d32a5e32e53c6b7e290 100644 (file)
@@ -24,7 +24,7 @@
  *
  * -------------------------------------------------------------------------- */
 
-#include "sampleActionEditor.h"
+#include "gui/dialogs/actionEditor/sampleActionEditor.h"
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/midiEvent.h"
 #include "glue/actionEditor.h"
 #include "glue/channel.h"
 #include "gui/elems/basics/box.h"
+#include "gui/ui.h"
 #include <string>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdSampleActionEditor::gdSampleActionEditor(ID channelId, m::Conf::Data& conf)
 : gdBaseActionEditor(channelId, conf)
 , m_barPadding(0, 0, w() - 232, G_GUI_UNIT)
 , m_sampleActionEditor(0, 0, this)
-, m_envelopeEditor(0, 0, "Volume", this)
+, m_envelopeEditor(0, 0, g_ui.langMapper.get(LangMap::ACTIONEDITOR_VOLUME), this)
 , m_actionType(0, 0, 80, G_GUI_UNIT)
 {
        end();
@@ -52,11 +55,11 @@ gdSampleActionEditor::gdSampleActionEditor(ID channelId, m::Conf::Data& conf)
        m_barTop.add(&zoomOutBtn);
        m_barTop.resizable(m_barPadding);
 
-       m_actionType.addItem("Key press");
-       m_actionType.addItem("Key release");
-       m_actionType.addItem("Stop sample");
+       m_actionType.addItem(g_ui.langMapper.get(LangMap::ACTIONEDITOR_KEYPRESS));
+       m_actionType.addItem(g_ui.langMapper.get(LangMap::ACTIONEDITOR_KEYRELEASE));
+       m_actionType.addItem(g_ui.langMapper.get(LangMap::ACTIONEDITOR_STOPSAMPLE));
        m_actionType.showItem(0);
-       m_actionType.copy_tooltip("Action type to add");
+       m_actionType.copy_tooltip(g_ui.langMapper.get(LangMap::ACTIONEDITOR_LABEL_ACTIONTYPE));
        if (!canChangeActionType())
                m_actionType.deactivate();
 
index c777498a53fc8f7d587f274b7c984ddd7c1c1a07..d30f6787573868b79c4379f3b1059b79bedbcc8b 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "beatsInput.h"
+#include "gui/dialogs/beatsInput.h"
 #include "core/const.h"
 #include "glue/main.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
+#include "gui/elems/basics/flex.h"
 #include "gui/elems/basics/input.h"
-#include "mainWindow.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <cstring>
 
-extern giada::v::gdMainWindow* mainWin;
+extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
 gdBeatsInput::gdBeatsInput(int beats, int bars)
-: gdWindow(u::gui::centerWindowX(180), u::gui::centerWindowY(36), 180, 36, "Beats")
+: gdWindow(u::gui::getCenterWinBounds(180, 36), "Beats")
 {
-       set_modal();
+       geFlex* container = new geFlex(getContentBounds().reduced({G_GUI_OUTER_MARGIN}), Direction::HORIZONTAL, G_GUI_INNER_MARGIN);
+       {
+               m_beats = new geInput(0, 0, 0, 0);
+               m_bars  = new geInput(0, 0, 0, 0);
+               m_ok    = new geButton(g_ui.langMapper.get(LangMap::COMMON_OK));
+               container->add(m_beats);
+               container->add(m_bars);
+               container->add(m_ok, 70);
+               container->end();
+       }
 
-       begin();
-       m_beats = new geInput(8, 8, 43, G_GUI_UNIT);
-       m_bars  = new geInput(m_beats->x() + m_beats->w() + 4, 8, 43, G_GUI_UNIT);
-       m_ok    = new geButton(m_bars->x() + m_bars->w() + 4, 8, 70, G_GUI_UNIT, "Ok");
-       end();
+       add(container);
 
        m_beats->maximum_size(2);
        m_beats->value(std::to_string(beats).c_str());
@@ -59,24 +65,16 @@ gdBeatsInput::gdBeatsInput(int beats, int bars)
        m_bars->type(FL_INT_INPUT);
 
        m_ok->shortcut(FL_Enter);
-       m_ok->callback(cb_update, (void*)this);
+       m_ok->onClick = [this]() {
+               if (!strcmp(m_beats->value(), "") || !strcmp(m_bars->value(), ""))
+                       return;
+               c::main::setBeats(atoi(m_beats->value()), atoi(m_bars->value()));
+               do_callback();
+       };
 
+       set_modal();
        u::gui::setFavicon(this);
        setId(WID_BEATS);
        show();
 }
-
-/* -------------------------------------------------------------------------- */
-
-void gdBeatsInput::cb_update(Fl_Widget* /*w*/, void* p) { ((gdBeatsInput*)p)->cb_update(); }
-
-/* -------------------------------------------------------------------------- */
-
-void gdBeatsInput::cb_update()
-{
-       if (!strcmp(m_beats->value(), "") || !strcmp(m_bars->value(), ""))
-               return;
-       c::main::setBeats(atoi(m_beats->value()), atoi(m_bars->value()));
-       do_callback();
-}
 } // namespace giada::v
\ No newline at end of file
index 5a6872482615ba648291a0fdba91abac8bafdad4..09dfccd848c570f3ee6bd8e31e324d9c9edb621f 100644 (file)
@@ -30,7 +30,6 @@
 #include "window.h"
 
 class geInput;
-class geCheck;
 
 namespace giada::v
 {
@@ -41,9 +40,6 @@ public:
        gdBeatsInput(int beats, int bars);
 
 private:
-       static void cb_update(Fl_Widget* /*w*/, void* p);
-       void        cb_update();
-
        geInput*  m_beats;
        geInput*  m_bars;
        geButton* m_ok;
index b84c6552c00f953fbbf038be7e6f865d2a623b73..56e745fef35fc2d17355e1ccd35d8b03c2d69ff0 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "bpmInput.h"
+#include "gui/dialogs/bpmInput.h"
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/mixer.h"
 #include "glue/main.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/flex.h"
 #include "gui/elems/basics/input.h"
-#include "mainWindow.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <cstring>
 
-extern giada::v::gdMainWindow* mainWin;
+extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
 gdBpmInput::gdBpmInput(const char* label)
-: gdWindow(u::gui::centerWindowX(144), u::gui::centerWindowY(36), 144, 36, "Bpm")
+: gdWindow(u::gui::getCenterWinBounds(180, 36), "Bpm")
 {
-       set_modal();
+       geFlex* container = new geFlex(getContentBounds().reduced({G_GUI_OUTER_MARGIN}), Direction::HORIZONTAL, G_GUI_INNER_MARGIN);
+       {
+               m_input_a = new geInput(0, 0, 0, 0);
+               m_input_b = new geInput(0, 0, 0, 0);
+               m_ok      = new geButton(g_ui.langMapper.get(LangMap::COMMON_OK));
+               container->add(m_input_a);
+               container->add(m_input_b);
+               container->add(m_ok, 70);
+               container->end();
+       }
 
-       begin();
-       input_a = new geInput(8, 8, 30, G_GUI_UNIT);
-       input_b = new geInput(42, 8, 20, G_GUI_UNIT);
-       ok      = new geButton(66, 8, 70, G_GUI_UNIT, "Ok");
-       end();
+       add(container);
 
        std::vector<std::string> parts = u::string::split(label, ".");
 
-       input_a->maximum_size(3);
-       input_a->type(FL_INT_INPUT);
-       input_a->value(parts[0].c_str());
+       m_input_a->maximum_size(3);
+       m_input_a->type(FL_INT_INPUT);
+       m_input_a->value(parts[0].c_str());
 
-       input_b->maximum_size(1);
-       input_b->type(FL_INT_INPUT);
-       input_b->value(parts[1].c_str());
+       m_input_b->maximum_size(1);
+       m_input_b->type(FL_INT_INPUT);
+       m_input_b->value(parts[1].c_str());
 
-       ok->shortcut(FL_Enter);
-       ok->callback(cb_update, (void*)this);
+       m_ok->shortcut(FL_Enter);
+       m_ok->onClick = [this]() {
+               if (strcmp(m_input_a->value(), "") == 0)
+                       return;
+               c::main::setBpm(m_input_a->value(), m_input_b->value());
+               do_callback();
+       };
 
+       set_modal();
        u::gui::setFavicon(this);
        setId(WID_BPM);
        show();
 }
-
-/* -------------------------------------------------------------------------- */
-
-void gdBpmInput::cb_update(Fl_Widget* /*w*/, void* p) { ((gdBpmInput*)p)->cb_update(); }
-
-/* -------------------------------------------------------------------------- */
-
-void gdBpmInput::cb_update()
-{
-       if (strcmp(input_a->value(), "") == 0)
-               return;
-       c::main::setBpm(input_a->value(), input_b->value());
-       do_callback();
-}
 } // namespace giada::v
\ No newline at end of file
index 8658e9ad8b70f8025297b2ee322085ba3d5c23c5..34d51b9c5b7e05a92a58f4e057141bb3f204fa59 100644 (file)
@@ -40,12 +40,9 @@ public:
        gdBpmInput(const char* label); // pointer to mainWin->timing->bpm->label()
 
 private:
-       static void cb_update(Fl_Widget* /*w*/, void* p);
-       void        cb_update();
-
-       geInput*  input_a;
-       geInput*  input_b;
-       geButton* ok;
+       geInput*  m_input_a;
+       geInput*  m_input_b;
+       geButton* m_ok;
 };
 } // namespace giada::v
 
index 1ed00285da2e668f9834c8c9d4f9afb47ae69b85..9f4fb449cb063c3ebccace8f3a9c510039744a3b 100644 (file)
 #include "gui/elems/basics/input.h"
 #include "gui/elems/basics/progress.h"
 #include "gui/elems/fileBrowser.h"
+#include "gui/ui.h"
 #include "utils/fs.h"
 #include "utils/gui.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdBrowserBase::gdBrowserBase(const std::string& title, const std::string& path,
@@ -50,9 +53,9 @@ gdBrowserBase::gdBrowserBase(const std::string& title, const std::string& path,
        set_non_modal();
 
        begin();
-       
+
        groupTop    = new Fl_Group(8, 8, w() - 16, 48);
-       hiddenFiles = new geCheck(groupTop->x(), groupTop->y(), 400, 20, "Show hidden files");
+       hiddenFiles = new geCheck(groupTop->x(), groupTop->y(), 400, 20, g_ui.langMapper.get(LangMap::BROWSER_SHOWHIDDENFILES));
        where       = new geInput(groupTop->x(), hiddenFiles->y() + hiddenFiles->h() + 8, 20, 20);
        updir       = new geButton(groupTop->x() + groupTop->w() - 20, where->y(), 20, 20, "", updirOff_xpm, updirOn_xpm);
        groupTop->end();
@@ -73,7 +76,7 @@ gdBrowserBase::gdBrowserBase(const std::string& title, const std::string& path,
 
        Fl_Group* groupButtons = new Fl_Group(8, browser->y() + browser->h() + 8, w() - 16, 20);
        ok                     = new geButton(w() - 88, groupButtons->y(), 80, 20);
-       cancel                 = new geButton(w() - ok->w() - 96, groupButtons->y(), 80, 20, "Cancel");
+       cancel                 = new geButton(w() - ok->w() - 96, groupButtons->y(), 80, 20, g_ui.langMapper.get(LangMap::COMMON_CANCEL));
        geBox* spacer          = new geBox(8, groupButtons->y(), cancel->x() - 16, 20);
        groupButtons->resizable(spacer);
        groupButtons->end();
index 69ea65ac78017b02e40bb009dced10ada2a30102..1dffcb5a5c84380511ca4f6fecb665015967f1d6 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "browserDir.h"
+#include "gui/dialogs/browser/browserDir.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
 #include "gui/elems/fileBrowser.h"
+#include "gui/ui.h"
 #include "utils/fs.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdBrowserDir::gdBrowserDir(const std::string& title, const std::string& path,
@@ -40,7 +43,7 @@ gdBrowserDir::gdBrowserDir(const std::string& title, const std::string& path,
 
        browser->callback(cb_down, (void*)this);
 
-       ok->label("Select");
+       ok->label(g_ui.langMapper.get(LangMap::COMMON_SELECT));
        ok->callback(cb_load, (void*)this);
        ok->shortcut(FL_ENTER);
 
index 5b4d90fecc0e88c3b049b23983c1dc96bf01615d..237b3d9da89a6e230ff41cecc33d536dae690e5f 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "browserLoad.h"
+#include "gui/dialogs/browser/browserLoad.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
 #include "gui/elems/fileBrowser.h"
+#include "gui/ui.h"
 #include "utils/fs.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdBrowserLoad::gdBrowserLoad(const std::string& title, const std::string& path,
@@ -40,7 +43,7 @@ gdBrowserLoad::gdBrowserLoad(const std::string& title, const std::string& path,
 
        browser->callback(cb_down, (void*)this);
 
-       ok->label("Load");
+       ok->label(g_ui.langMapper.get(LangMap::COMMON_LOAD));
        ok->callback(cb_load, (void*)this);
        ok->shortcut(FL_ENTER);
 
index 56f18c0b2fe12e8cc1d434d62cf71f1a86ae3211..207da682048d4aebb876c33963eb049be00502d8 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "browserSave.h"
+#include "gui/dialogs/browser/browserSave.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
 #include "gui/elems/fileBrowser.h"
+#include "gui/ui.h"
 #include "utils/fs.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdBrowserSave::gdBrowserSave(const std::string& title, const std::string& path,
@@ -45,7 +48,7 @@ gdBrowserSave::gdBrowserSave(const std::string& title, const std::string& path,
 
        browser->callback(cb_down, (void*)this);
 
-       ok->label("Save");
+       ok->label(g_ui.langMapper.get(LangMap::COMMON_SAVE));
        ok->callback(cb_save, (void*)this);
        ok->shortcut(FL_ENTER);
 
index ed9ac9c1c35dbd62bc7e4f85922d799a5ede0bc3..71ba778080723ec17b257e0092fd836d0826e877 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "channelNameInput.h"
+#include "gui/dialogs/channelNameInput.h"
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/model/model.h"
 #include "glue/channel.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/flex.h"
 #include "gui/elems/basics/input.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 gdChannelNameInput::gdChannelNameInput(const c::channel::Data& d)
-: gdWindow(u::gui::centerWindowX(400), u::gui::centerWindowY(64), 400, 64, "New channel name")
+: gdWindow(u::gui::getCenterWinBounds(400, 64), g_ui.langMapper.get(LangMap::CHANNELNAME_TITLE))
 , m_data(d)
 {
-       set_modal();
+       geFlex* container = new geFlex(getContentBounds().reduced({G_GUI_OUTER_MARGIN}), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
+       {
+               m_name = new geInput(0, 0, 0, 0);
+
+               geFlex* footer = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
+               {
+                       m_ok     = new geButton(g_ui.langMapper.get(LangMap::COMMON_OK));
+                       m_cancel = new geButton(g_ui.langMapper.get(LangMap::COMMON_CANCEL));
+                       footer->add(new geBox());
+                       footer->add(m_cancel, 70);
+                       footer->add(m_ok, 70);
+                       footer->end();
+               }
+               container->add(m_name, G_GUI_UNIT);
+               container->add(footer, G_GUI_UNIT);
+               container->end();
+       }
 
-       begin();
-       m_name   = new geInput(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, w() - (G_GUI_OUTER_MARGIN * 2), G_GUI_UNIT);
-       m_ok     = new geButton(w() - 70 - G_GUI_OUTER_MARGIN, m_name->y() + m_name->h() + G_GUI_OUTER_MARGIN, 70, G_GUI_UNIT, "Ok");
-       m_cancel = new geButton(m_ok->x() - 70 - G_GUI_OUTER_MARGIN, m_ok->y(), 70, G_GUI_UNIT, "Cancel");
-       end();
+       add(container);
 
        m_name->value(m_data.name.c_str());
 
        m_ok->shortcut(FL_Enter);
-       m_ok->callback(cb_update, (void*)this);
+       m_ok->onClick = [this]() {
+               c::channel::setName(m_data.id, m_name->value());
+               do_callback();
+       };
 
-       m_cancel->callback(cb_cancel, (void*)this);
+       m_cancel->onClick = [this]() {
+               do_callback();
+       };
 
+       set_modal();
        u::gui::setFavicon(this);
        setId(WID_SAMPLE_NAME);
        show();
 }
-
-/* -------------------------------------------------------------------------- */
-
-void gdChannelNameInput::cb_update(Fl_Widget* /*w*/, void* p) { ((gdChannelNameInput*)p)->cb_update(); }
-void gdChannelNameInput::cb_cancel(Fl_Widget* /*w*/, void* p) { ((gdChannelNameInput*)p)->cb_cancel(); }
-
-/* -------------------------------------------------------------------------- */
-
-void gdChannelNameInput::cb_cancel()
-{
-       do_callback();
-}
-
-/* -------------------------------------------------------------------------- */
-
-void gdChannelNameInput::cb_update()
-{
-       c::channel::setName(m_data.id, m_name->value());
-       do_callback();
-}
-
-} // namespace v
-} // namespace giada
+} // namespace giada::v
\ No newline at end of file
index c9286ae6844dedc64d6fec5f547604bfc0c4731a..44e86dfb89616726522bbe164bd14b97d2275d3b 100644 (file)
@@ -45,11 +45,6 @@ public:
        gdChannelNameInput(const c::channel::Data& d);
 
 private:
-       static void cb_update(Fl_Widget* /*w*/, void* p);
-       static void cb_cancel(Fl_Widget* /*w*/, void* p);
-       void        cb_update();
-       void        cb_cancel();
-
        const c::channel::Data& m_data;
 
        geInput*  m_name;
index 29048a885da31f602b0bba55df1b9b5eb58de142..75eee819002946f1a4398b7825f11615e6f74fed 100644 (file)
 #include "gui/elems/config/tabMidi.h"
 #include "gui/elems/config/tabMisc.h"
 #include "gui/elems/config/tabPlugins.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdConfig::gdConfig(int w, int h, m::Conf::Data& conf)
-: gdWindow(u::gui::getCenterWinBounds(w, h), "Configuration")
+: gdWindow(u::gui::getCenterWinBounds(w, h), g_ui.langMapper.get(LangMap::CONFIG_TITLE))
 {
        const geompp::Rect<int> bounds = getContentBounds().reduced(G_GUI_OUTER_MARGIN);
 
@@ -71,8 +74,8 @@ gdConfig::gdConfig(int w, int h, m::Conf::Data& conf)
 
                geFlex* footer = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       geButton* save   = new geButton("Save");
-                       geButton* cancel = new geButton("Cancel");
+                       geButton* save   = new geButton(g_ui.langMapper.get(LangMap::COMMON_SAVE));
+                       geButton* cancel = new geButton(g_ui.langMapper.get(LangMap::COMMON_CANCEL));
                        save->onClick    = [this]() { saveConfig(); };
                        cancel->onClick  = [this]() { do_callback(); };
 
index 51fae3cf8c29b48f46ebecd002ff16a233b2800f..4c87186b6ecfb3173abfa341e81884c2346f53e0 100644 (file)
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/flex.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/log.h"
 #include "utils/string.h"
 #include <cassert>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdKeyGrabber::gdKeyGrabber(int key)
-: gdWindow(300, 126, "Key configuration")
+: gdWindow(300, 126, g_ui.langMapper.get(LangMap::KEYGRABBER_TITLE))
 , onSetKey(nullptr)
 , m_key(key)
 {
@@ -49,8 +52,8 @@ gdKeyGrabber::gdKeyGrabber(int key)
 
                geFlex* footer = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       m_clear  = new geButton("Clear");
-                       m_cancel = new geButton("Close");
+                       m_clear  = new geButton(g_ui.langMapper.get(LangMap::COMMON_CLEAR));
+                       m_cancel = new geButton(g_ui.langMapper.get(LangMap::COMMON_CLOSE));
 
                        footer->add(new geBox()); // Spacer
                        footer->add(m_clear, 80);
@@ -88,7 +91,7 @@ gdKeyGrabber::gdKeyGrabber(int key)
 
 void gdKeyGrabber::rebuild()
 {
-       std::string tmp = "Press a key.\n\nCurrent binding: " + u::gui::keyToString(m_key);
+       std::string tmp = g_ui.langMapper.get(LangMap::KEYGRABBER_BODY) + u::gui::keyToString(m_key);
        m_text->copy_label(tmp.c_str());
 }
 
index c0c6582bdba122599c8a52a6fe6086dd3559bc35..603903e87bb92ee72cedc1459f3a59057a43a4e2 100644 (file)
@@ -87,45 +87,44 @@ gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** arg
        Fl_Tooltip::size(G_GUI_FONT_SIZE_BASE);
        Fl_Tooltip::enable(m_conf.showTooltips);
 
-       size_range(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT);
-
-       mainMenu      = new v::geMainMenu(0, 0);
-       mainIO        = new v::geMainIO(0, 0, 0, 0);
-       mainTransport = new v::geMainTransport(8, 39);
-       mainTimer     = new v::geMainTimer(571, 44);
-       sequencer     = new v::geSequencer(100, 78, 609, 30);
-       keyboard      = new v::geKeyboard(8, 122, w() - 16, 380);
-
-       /* zone 1 - menus, and I/O tools */
-
-       geFlex* zone1 = new geFlex(getContentBounds().reduced(G_GUI_OUTER_MARGIN).withH(G_GUI_UNIT),
-           Direction::HORIZONTAL, G_GUI_INNER_MARGIN);
-       zone1->add(mainMenu, 300);
-       zone1->add(new Fl_Box(0, 0, 0, 0));
-       zone1->add(mainIO, 430);
-       zone1->end();
-
-       /* zone 2 - mainTransport and timing tools */
-
-       Fl_Group* zone2 = new Fl_Group(8, mainTransport->y(), W - 16, mainTransport->h());
-       zone2->add(mainTransport);
-       zone2->resizable(new Fl_Box(mainTransport->x() + mainTransport->w() + 4, zone2->y(), 80, 20));
-       zone2->add(mainTimer);
-
-       /* zone 3 - beat meter */
-
-       Fl_Group* zone3 = new Fl_Group(8, sequencer->y(), W - 16, sequencer->h());
-       zone3->add(sequencer);
-
-       /* zone 4 - the keyboard (Fl_Group is unnecessary here, keyboard is
-        * a group by itself) */
-
-       resizable(keyboard);
-
-       add(zone1);
-       add(zone2);
-       add(zone3);
-       add(keyboard);
+       geFlex* container = new geFlex(getContentBounds().reduced({G_GUI_OUTER_MARGIN}), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
+       {
+               /* zone 1 - menus, and I/O tools */
+
+               geFlex* zone1 = new geFlex(Direction::HORIZONTAL, G_GUI_INNER_MARGIN);
+               {
+                       mainMenu = new v::geMainMenu();
+                       mainIO   = new v::geMainIO();
+                       zone1->add(mainMenu, 350);
+                       zone1->add(new geBox());
+                       zone1->add(mainIO, 430);
+                       zone1->end();
+               }
+
+               /* zone 2 - mainTransport and timing tools */
+
+               geFlex* zone2 = new geFlex(Direction::HORIZONTAL, G_GUI_INNER_MARGIN);
+               {
+                       mainTransport = new v::geMainTransport();
+                       mainTimer     = new v::geMainTimer();
+                       zone2->add(mainTransport, 400);
+                       zone2->add(new geBox());
+                       zone2->add(mainTimer, 237, {2, 0, 3, 0});
+                       zone2->end();
+               }
+
+               sequencer = new v::geSequencer();
+               keyboard  = new v::geKeyboard();
+
+               container->add(zone1, G_GUI_UNIT);
+               container->add(zone2, 30, {5, 0, 0, 0});
+               container->add(sequencer, 40, {4, 80, 4, 80});
+               container->add(keyboard);
+               container->end();
+       }
+
+       add(container);
+       resizable(container);
 
        callback([](Fl_Widget* /*w*/, void* /*v*/) {
                if (Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape)
@@ -134,6 +133,7 @@ gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** arg
        });
        u::gui::setFavicon(this);
 
+       size_range(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT);
        refresh();
 
        show(argc, argv);
index b41afffbfa85680dce06ae8434245be83b4eaaab..77c099e188d75b21e9832048c8ea4cf522fb22bc 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
+#include "gui/dialogs/midiIO/midiInputChannel.h"
 #include "core/conf.h"
 #include "core/const.h"
-#include "utils/gui.h"
-#include "utils/log.h"
-#include <FL/Fl_Pack.H>
-#include <cassert>
-#include <cstddef>
-#ifdef WITH_VST
-#include "core/plugins/plugin.h"
-#endif
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/scrollPack.h"
 #include "gui/elems/midiIO/midiLearner.h"
 #include "gui/elems/midiIO/midiLearnerPack.h"
-#include "midiInputChannel.h"
+#include "gui/ui.h"
+#include "utils/gui.h"
+#include "utils/log.h"
 #include "utils/string.h"
+#include <FL/Fl_Pack.H>
+#include <cassert>
+#include <cstddef>
+#ifdef WITH_VST
+#include "core/plugins/plugin.h"
+#endif
+
+extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
 geChannelLearnerPack::geChannelLearnerPack(int x, int y, const c::io::Channel_InputData& channel)
-: geMidiLearnerPack(x, y, "Channel")
+: geMidiLearnerPack(x, y, g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_CHANNEL))
 {
        setCallbacks(
            [channelId = channel.channelId](int param) { c::io::channel_startMidiLearn(param, channelId); },
            [channelId = channel.channelId](int param) { c::io::channel_clearMidiLearn(param, channelId); });
-       addMidiLearner("key press", G_MIDI_IN_KEYPRESS);
-       addMidiLearner("key release", G_MIDI_IN_KEYREL);
-       addMidiLearner("key kill", G_MIDI_IN_KILL);
-       addMidiLearner("arm", G_MIDI_IN_ARM);
-       addMidiLearner("mute", G_MIDI_IN_MUTE);
-       addMidiLearner("solo", G_MIDI_IN_SOLO);
-       addMidiLearner("volume", G_MIDI_IN_VOLUME);
-       addMidiLearner("pitch", G_MIDI_IN_PITCH, /*visible=*/channel.channelType == ChannelType::SAMPLE);
-       addMidiLearner("read actions", G_MIDI_IN_READ_ACTIONS, /*visible=*/channel.channelType == ChannelType::SAMPLE);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_KEYPRESS), G_MIDI_IN_KEYPRESS);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_KEYREL), G_MIDI_IN_KEYREL);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_KEYKILL), G_MIDI_IN_KILL);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_ARM), G_MIDI_IN_ARM);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_MUTE), G_MIDI_IN_MUTE);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_SOLO), G_MIDI_IN_SOLO);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_VOLUME), G_MIDI_IN_VOLUME);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_PITCH), G_MIDI_IN_PITCH, /*visible=*/channel.channelType == ChannelType::SAMPLE);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_LEARN_READACTIONS), G_MIDI_IN_READ_ACTIONS, /*visible=*/channel.channelType == ChannelType::SAMPLE);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -114,21 +117,19 @@ void gePluginLearnerPack::update(const c::io::PluginData& d, bool enabled)
 /* -------------------------------------------------------------------------- */
 
 gdMidiInputChannel::gdMidiInputChannel(ID channelId, m::Conf::Data& c)
-: gdMidiInputBase(c.midiInputX, c.midiInputY, c.midiInputW, c.midiInputH, "", c)
+: gdMidiInputBase(c.midiInputX, c.midiInputY, c.midiInputW, c.midiInputH, g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_TITLE), c)
 , m_channelId(channelId)
 , m_data(c::io::channel_getInputData(channelId))
 {
        end();
 
-       copy_label(std::string("MIDI Input Setup (channel " + std::to_string(channelId) + ")").c_str());
-
        /* Header */
 
        geGroup* groupHeader = new geGroup(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN);
-       m_enable             = new geCheck(0, 0, 120, G_GUI_UNIT, "Enable MIDI input");
+       m_enable             = new geCheck(0, 0, 120, G_GUI_UNIT, g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_ENABLE));
        m_channel            = new geChoice(m_enable->x() + m_enable->w() + 44, 0, 120, G_GUI_UNIT);
        m_veloAsVol          = new geCheck(0, m_enable->y() + m_enable->h() + G_GUI_OUTER_MARGIN, w() - 16, G_GUI_UNIT,
-        "Velocity drives volume (Sample Channels)");
+        g_ui.langMapper.get(LangMap::MIDIINPUT_CHANNEL_VELOCITYDRIVESVOL));
        groupHeader->add(m_enable);
        groupHeader->add(m_channel);
        groupHeader->add(m_veloAsVol);
@@ -148,7 +149,7 @@ gdMidiInputChannel::gdMidiInputChannel(ID channelId, m::Conf::Data& c)
 
        geGroup* groupButtons = new geGroup(G_GUI_OUTER_MARGIN, m_container->y() + m_container->h() + G_GUI_OUTER_MARGIN);
        geBox*   spacer       = new geBox(0, 0, w() - 80, G_GUI_UNIT); // spacer window border <-> buttons
-       m_ok                  = new geButton(w() - 96, 0, 80, G_GUI_UNIT, "Close");
+       m_ok                  = new geButton(w() - 96, 0, 80, G_GUI_UNIT, g_ui.langMapper.get(LangMap::COMMON_CLOSE));
        groupButtons->add(spacer);
        groupButtons->add(m_ok);
        groupButtons->resizable(spacer);
index 2a79e12170318abd5871c6f7d24c91d24b920d36..fad43291b5ae73865fe59866fac223420f2882cc 100644 (file)
@@ -24,7 +24,7 @@
  *
  * -------------------------------------------------------------------------- */
 
-#include "midiInputMaster.h"
+#include "gui/dialogs/midiIO/midiInputMaster.h"
 #include "core/conf.h"
 #include "core/const.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/group.h"
 #include "gui/elems/basics/scrollPack.h"
 #include "gui/elems/midiIO/midiLearner.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
-#include <FL/Fl_Pack.H>
+
+extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
@@ -44,15 +46,15 @@ geMasterLearnerPack::geMasterLearnerPack(int x, int y)
        setCallbacks(
            [](int param) { c::io::master_startMidiLearn(param); },
            [](int param) { c::io::master_clearMidiLearn(param); });
-       addMidiLearner("rewind", G_MIDI_IN_REWIND);
-       addMidiLearner("play/stop", G_MIDI_IN_START_STOP);
-       addMidiLearner("action recording", G_MIDI_IN_ACTION_REC);
-       addMidiLearner("input recording", G_MIDI_IN_INPUT_REC);
-       addMidiLearner("metronome", G_MIDI_IN_METRONOME);
-       addMidiLearner("input volume", G_MIDI_IN_VOLUME_IN);
-       addMidiLearner("output volume", G_MIDI_IN_VOLUME_OUT);
-       addMidiLearner("sequencer Ã—2", G_MIDI_IN_BEAT_DOUBLE);
-       addMidiLearner("sequencer Ã·2", G_MIDI_IN_BEAT_HALF);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_REWIND), G_MIDI_IN_REWIND);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_PLAYSTOP), G_MIDI_IN_START_STOP);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_ACTIONREC), G_MIDI_IN_ACTION_REC);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_INPUTREC), G_MIDI_IN_INPUT_REC);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_METRONOME), G_MIDI_IN_METRONOME);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_INVOLUME), G_MIDI_IN_VOLUME_IN);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_OUTVOLUME), G_MIDI_IN_VOLUME_OUT);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_SEQDOUBLE), G_MIDI_IN_BEAT_DOUBLE);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_LEARN_SEQHALF), G_MIDI_IN_BEAT_HALF);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -76,19 +78,19 @@ void geMasterLearnerPack::update(const c::io::Master_InputData& d)
 /* -------------------------------------------------------------------------- */
 
 gdMidiInputMaster::gdMidiInputMaster(m::Conf::Data& c)
-: gdMidiInputBase(c.midiInputX, c.midiInputY, 300, 284, "MIDI Input Setup (global)", c)
+: gdMidiInputBase(c.midiInputX, c.midiInputY, 300, 284, g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_TITLE), c)
 {
        end();
 
        geGroup* groupHeader = new geGroup(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN);
-       m_enable             = new geCheck(0, 0, 120, G_GUI_UNIT, "Enable MIDI input");
+       m_enable             = new geCheck(0, 0, 120, G_GUI_UNIT, g_ui.langMapper.get(LangMap::MIDIINPUT_MASTER_ENABLE));
        m_channel            = new geChoice(m_enable->x() + m_enable->w() + 44, 0, 120, G_GUI_UNIT);
        groupHeader->resizable(nullptr);
        groupHeader->add(m_enable);
        groupHeader->add(m_channel);
 
        m_learners = new geMasterLearnerPack(G_GUI_OUTER_MARGIN, groupHeader->y() + groupHeader->h() + G_GUI_OUTER_MARGIN);
-       m_ok       = new geButton(w() - 88, m_learners->y() + m_learners->h() + G_GUI_OUTER_MARGIN, 80, G_GUI_UNIT, "Close");
+       m_ok       = new geButton(w() - 88, m_learners->y() + m_learners->h() + G_GUI_OUTER_MARGIN, 80, G_GUI_UNIT, g_ui.langMapper.get(LangMap::COMMON_CLOSE));
 
        add(groupHeader);
        add(m_learners);
index 7635ab9f77eb7bb1b4f9ee00ccd7b947fe744f00..0eba87fa592f9883f4e3be08abf53499e0967c9b 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "midiOutputBase.h"
+#include "gui/dialogs/midiIO/midiOutputBase.h"
 #include "glue/io.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/midiIO/midiLearner.h"
+#include "gui/ui.h"
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 geLightningLearnerPack::geLightningLearnerPack(int x, int y, ID channelId)
 : geMidiLearnerPack(x, y)
@@ -39,9 +40,9 @@ geLightningLearnerPack::geLightningLearnerPack(int x, int y, ID channelId)
        setCallbacks(
            [channelId](int param) { c::io::channel_startMidiLearn(param, channelId); },
            [channelId](int param) { c::io::channel_clearMidiLearn(param, channelId); });
-       addMidiLearner("playing", G_MIDI_OUT_L_PLAYING);
-       addMidiLearner("mute", G_MIDI_OUT_L_MUTE);
-       addMidiLearner("solo", G_MIDI_OUT_L_SOLO);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIOUTPUT_CHANNEL_LEARN_PLAYING), G_MIDI_OUT_L_PLAYING);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIOUTPUT_CHANNEL_LEARN_MUTE), G_MIDI_OUT_L_MUTE);
+       addMidiLearner(g_ui.langMapper.get(LangMap::MIDIOUTPUT_CHANNEL_LEARN_SOLO), G_MIDI_OUT_L_SOLO);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -59,7 +60,7 @@ void geLightningLearnerPack::update(const c::io::Channel_OutputData& d)
 /* -------------------------------------------------------------------------- */
 
 gdMidiOutputBase::gdMidiOutputBase(int w, int h, ID channelId)
-: gdWindow(w, h, "Midi Output Setup")
+: gdWindow(w, h, g_ui.langMapper.get(LangMap::MIDIOUTPUT_CHANNEL_TITLE))
 , m_channelId(channelId)
 {
 }
@@ -89,13 +90,4 @@ void gdMidiOutputBase::cb_enableLightning()
 {
        c::io::channel_enableMidiLightning(m_channelId, m_enableLightning->value());
 }
-
-/* -------------------------------------------------------------------------- */
-
-void gdMidiOutputBase::setTitle(ID channelId)
-{
-       std::string tmp = "MIDI Output Setup (channel " + std::to_string(channelId) + ")";
-       copy_label(tmp.c_str());
-}
-} // namespace v
-} // namespace giada
+} // namespace giada::v
index 28b9e8fd8ac2be3aa34f844248aa04b005206a7f..aea7420e79d556cfdc6831dcf0b1dc0b8eab267d 100644 (file)
@@ -73,11 +73,6 @@ protected:
        static void cb_enableLightning(Fl_Widget* /*w*/, void* p);
        void        cb_enableLightning();
 
-       /* setTitle
-        * set window title. */
-
-       void setTitle(ID channelId);
-
        ID m_channelId;
 
        c::io::Channel_OutputData m_data;
index ca318904e31c6f2d115597c972cbdcb662fa1099..977274d6cca6ac302d91eed239e87ecfd385f2f2 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "midiOutputMidiCh.h"
+#include "gui/dialogs/midiIO/midiOutputMidiCh.h"
 #include "glue/io.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/choice.h"
 #include "gui/elems/midiIO/midiLearner.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include <FL/Fl_Pack.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdMidiOutputMidiCh::gdMidiOutputMidiCh(ID channelId)
 : gdMidiOutputBase(300, 168, channelId)
 {
        end();
-       setTitle(m_channelId + 1);
 
-       m_enableOut   = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 150, G_GUI_UNIT, "Enable MIDI output");
+       m_enableOut   = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 150, G_GUI_UNIT, g_ui.langMapper.get(LangMap::MIDIOUTPUT_CHANNEL_ENABLE));
        m_chanListOut = new geChoice(w() - 108, G_GUI_OUTER_MARGIN, 100, G_GUI_UNIT);
 
        m_enableLightning = new geCheck(G_GUI_OUTER_MARGIN, m_chanListOut->y() + m_chanListOut->h() + G_GUI_OUTER_MARGIN,
-           120, G_GUI_UNIT, "Enable MIDI lightning output");
+           120, G_GUI_UNIT, g_ui.langMapper.get(LangMap::MIDIOUTPUT_CHANNEL_ENABLE_LIGHTNING));
 
        m_learners = new geLightningLearnerPack(G_GUI_OUTER_MARGIN,
            m_enableLightning->y() + m_enableLightning->h() + G_GUI_OUTER_MARGIN, channelId);
 
-       m_close = new geButton(w() - 88, m_learners->y() + m_learners->h() + G_GUI_OUTER_MARGIN, 80, G_GUI_UNIT, "Close");
+       m_close = new geButton(w() - 88, m_learners->y() + m_learners->h() + G_GUI_OUTER_MARGIN, 80, G_GUI_UNIT,
+           g_ui.langMapper.get(LangMap::COMMON_CLOSE));
 
        add(m_enableOut);
        add(m_chanListOut);
index 0c0fde308a09db9873b7e81d8098dd8c37287f62..9ce092b8268f40b6b94dc5497ed85e36075b3082 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "midiOutputSampleCh.h"
+#include "gui/dialogs/midiIO/midiOutputSampleCh.h"
 #include "core/model/model.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/midiIO/midiLearner.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include <FL/Fl_Pack.H>
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 gdMidiOutputSampleCh::gdMidiOutputSampleCh(ID channelId)
 : gdMidiOutputBase(300, 140, channelId)
 {
        end();
-       setTitle(m_channelId);
 
-       m_enableLightning = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 120, 20, "Enable MIDI lightning output");
+       m_enableLightning = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 120, 20, g_ui.langMapper.get(LangMap::MIDIOUTPUT_CHANNEL_ENABLE_LIGHTNING));
 
        m_learners = new geLightningLearnerPack(G_GUI_OUTER_MARGIN,
            m_enableLightning->y() + m_enableLightning->h() + 8, channelId);
 
-       m_close = new geButton(w() - 88, m_learners->y() + m_learners->h() + 8, 80, 20, "Close");
+       m_close = new geButton(w() - 88, m_learners->y() + m_learners->h() + 8, 80, 20,
+           g_ui.langMapper.get(LangMap::COMMON_CLOSE));
 
        add(m_enableLightning);
        add(m_learners);
@@ -72,5 +73,4 @@ void gdMidiOutputSampleCh::rebuild()
        m_enableLightning->value(m_data.lightningEnabled);
        m_learners->update(m_data);
 }
-} // namespace v
-} // namespace giada
+} // namespace giada::v
index 03b897f2fb8f560c4b805522db00c2dac8ff3d22..e2d10b4f9d8b20fc21befa07b0d1b50c5be9bcfe 100644 (file)
 #include "gui/elems/basics/browser.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/flex.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include <FL/Fl_Group.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdMissingAssets::gdMissingAssets(const m::LoadState& state)
-: gdWindow(u::gui::getCenterWinBounds(400, 300), "Warning")
+: gdWindow(u::gui::getCenterWinBounds(400, 300), g_ui.langMapper.get(LangMap::COMMON_WARNING))
 {
        geFlex* container = new geFlex(getContentBounds().reduced({G_GUI_OUTER_MARGIN}), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
        {
                geFlex* body = new geFlex(Direction::VERTICAL, G_GUI_INNER_MARGIN);
                {
-                       geBox* textIntro = new geBox("This project contains missing assets.", FL_ALIGN_LEFT);
+                       geBox* textIntro = new geBox(g_ui.langMapper.get(LangMap::MISSINGASSETS_INTRO), FL_ALIGN_LEFT);
                        textIntro->color(G_COLOR_BLUE);
 
                        body->add(textIntro, G_GUI_UNIT);
@@ -52,7 +55,7 @@ gdMissingAssets::gdMissingAssets(const m::LoadState& state)
                                geBrowser* waves = new geBrowser();
                                for (const std::string& s : state.missingWaves)
                                        waves->add(s.c_str());
-                               body->add(new geBox("Audio files not found in the project folder:", FL_ALIGN_LEFT), G_GUI_UNIT);
+                               body->add(new geBox(g_ui.langMapper.get(LangMap::MISSINGASSETS_AUDIOFILES), FL_ALIGN_LEFT), G_GUI_UNIT);
                                body->add(waves);
                        }
 
@@ -61,7 +64,7 @@ gdMissingAssets::gdMissingAssets(const m::LoadState& state)
                                geBrowser* plugins = new geBrowser();
                                for (const std::string& s : state.missingPlugins)
                                        plugins->add(s.c_str());
-                               body->add(new geBox("Audio plug-ins not found globally:", FL_ALIGN_LEFT), G_GUI_UNIT);
+                               body->add(new geBox(g_ui.langMapper.get(LangMap::MISSINGASSETS_PLUGINS), FL_ALIGN_LEFT), G_GUI_UNIT);
                                body->add(plugins);
                        }
                        body->end();
@@ -69,7 +72,7 @@ gdMissingAssets::gdMissingAssets(const m::LoadState& state)
 
                geFlex* footer = new geFlex(Direction::HORIZONTAL);
                {
-                       geButton* close = new geButton("Close");
+                       geButton* close = new geButton(g_ui.langMapper.get(LangMap::COMMON_CLOSE));
                        close->onClick  = [this]() { do_callback(); };
                        footer->add(new geBox()); // Spacer
                        footer->add(close, 80);
index 1f06e17c0cd9138195d34522e08d07431c307357..3ded71cae90a0ea1a7095be96a7761b47dde8456 100644 (file)
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
+#include "gui/elems/basics/flex.h"
 #include "gui/elems/plugin/pluginBrowser.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, ID channelId, m::Conf::Data& c)
-: gdWindow(X, Y, W, H, "Available plugins")
+: gdWindow(X, Y, W, H, g_ui.langMapper.get(LangMap::PLUGINCHOOSER_TITLE))
 , m_conf(c)
 , m_channelId(channelId)
 {
-       begin();
-
-       /* top area */
-       Fl_Group* group_top = new Fl_Group(8, 8, w() - 16, 20);
-       sortMethod          = new geChoice(group_top->x(), group_top->y(), 180, 20, "Sort by", 0);
-       geBox* b1           = new geBox(sortMethod->x() + sortMethod->w(), group_top->y(), 100, 20); // spacer window border <-> menu
-       group_top->resizable(b1);
-       group_top->end();
-
-       /* center browser */
-       browser = new v::gePluginBrowser(8, 36, w() - 16, h() - 70);
-
-       /* ok/cancel buttons */
-       Fl_Group* group_btn = new Fl_Group(8, browser->y() + browser->h() + 8, w() - 16, h() - browser->h() - 16);
-       geBox*    b2        = new geBox(8, browser->y() + browser->h(), 100, 20); // spacer window border <-> buttons
-       addBtn              = new geButton(w() - 88, group_btn->y(), 80, 20, "Add");
-       cancelBtn           = new geButton(addBtn->x() - 88, group_btn->y(), 80, 20, "Cancel");
-       group_btn->resizable(b2);
-       group_btn->end();
-
-       end();
-
-       sortMethod->addItem("Name");
-       sortMethod->addItem("Category");
-       sortMethod->addItem("Manufacturer");
-       sortMethod->addItem("Format");
+       geFlex* container = new geFlex(getContentBounds().reduced({G_GUI_OUTER_MARGIN}), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
+       {
+               geFlex* header = new geFlex(Direction::HORIZONTAL, G_GUI_INNER_MARGIN);
+               {
+                       sortMethod = new geChoice(g_ui.langMapper.get(LangMap::PLUGINCHOOSER_SORTBY), 0);
+                       header->add(sortMethod, 180);
+                       header->add(new geBox());
+                       header->end();
+               }
+
+               browser = new v::gePluginBrowser(0, 0, 0, 0);
+
+               geFlex* footer = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
+               {
+                       addBtn    = new geButton(g_ui.langMapper.get(LangMap::COMMON_ADD));
+                       cancelBtn = new geButton(g_ui.langMapper.get(LangMap::COMMON_CANCEL));
+                       footer->add(new geBox());
+                       footer->add(cancelBtn, 80);
+                       footer->add(addBtn, 80);
+                       footer->end();
+               }
+
+               container->add(header, G_GUI_UNIT);
+               container->add(browser);
+               container->add(footer, G_GUI_UNIT);
+               container->end();
+       }
+
+       add(container);
+       resizable(container);
+
+       sortMethod->addItem(g_ui.langMapper.get(LangMap::PLUGINCHOOSER_SORTBY_NAME));
+       sortMethod->addItem(g_ui.langMapper.get(LangMap::PLUGINCHOOSER_SORTBY_CATEGORY));
+       sortMethod->addItem(g_ui.langMapper.get(LangMap::PLUGINCHOOSER_SORTBY_MANIFACTURER));
+       sortMethod->addItem(g_ui.langMapper.get(LangMap::PLUGINCHOOSER_SORTBY_FORMAT));
        sortMethod->showItem(m_conf.pluginSortMethod);
        sortMethod->onChange = [this](ID id) {
                c::plugin::sortPlugins(static_cast<m::PluginManager::SortMethod>(id));
@@ -78,7 +91,6 @@ gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, ID channelId, m::Co
        addBtn->shortcut(FL_Enter);
        cancelBtn->callback(cb_close, (void*)this);
 
-       resizable(browser);
        u::gui::setFavicon(this);
        show();
 }
index 02fee22c963fd6b728c62ce449141c3190b4b405..f1cbdd0212a1e589549835c1c1ac8d725713b71c 100644 (file)
 #include "gui/elems/mainWindow/keyboard/channel.h"
 #include "gui/elems/mainWindow/mainIO.h"
 #include "gui/elems/plugin/pluginElement.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <cassert>
 #include <string>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdPluginList::gdPluginList(ID channelId, m::Conf::Data& c)
@@ -83,14 +86,11 @@ void gdPluginList::rebuild()
        m_plugins = c::plugin::getPlugins(m_channelId);
 
        if (m_plugins.channelId == m::Mixer::MASTER_OUT_CHANNEL_ID)
-               label("Master Out Plug-ins");
+               label(g_ui.langMapper.get(LangMap::PLUGINLIST_TITLE_MASTEROUT));
        else if (m_plugins.channelId == m::Mixer::MASTER_IN_CHANNEL_ID)
-               label("Master In Plug-ins");
+               label(g_ui.langMapper.get(LangMap::PLUGINLIST_TITLE_MASTERIN));
        else
-       {
-               std::string l = "Channel " + u::string::iToString(m_plugins.channelId) + " Plug-ins";
-               copy_label(l.c_str());
-       }
+               label(g_ui.langMapper.get(LangMap::PLUGINLIST_TITLE_CHANNEL));
 
        /* Clear the previous list. */
 
@@ -100,7 +100,7 @@ void gdPluginList::rebuild()
        for (m::Plugin* plugin : m_plugins.plugins)
                list->addWidget(new gePluginElement(0, 0, c::plugin::getPlugin(*plugin, m_plugins.channelId)));
 
-       addPlugin = list->addWidget(new geButton(0, 0, 0, G_GUI_UNIT, "-- add new plugin --"));
+       addPlugin = list->addWidget(new geButton(0, 0, 0, G_GUI_UNIT, g_ui.langMapper.get(LangMap::PLUGINLIST_ADDPLUGIN)));
 
        addPlugin->callback(cb_addPlugin, (void*)this);
 }
index 194748f9fa7961c6667661137cff6f551d6bf965..562237fe8333d9d505201fab210bd507d4a6f9b7 100644 (file)
@@ -43,7 +43,6 @@
 #include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/statusButton.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
-#include "gui/elems/sampleEditor/boostTool.h"
 #include "gui/elems/sampleEditor/panTool.h"
 #include "gui/elems/sampleEditor/pitchTool.h"
 #include "gui/elems/sampleEditor/rangeTool.h"
@@ -51,6 +50,7 @@
 #include "gui/elems/sampleEditor/volumeTool.h"
 #include "gui/elems/sampleEditor/waveTools.h"
 #include "gui/elems/sampleEditor/waveform.h"
+#include "gui/ui.h"
 #include "sampleEditor.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <FL/Fl_Group.H>
 #include <cassert>
 #include <cmath>
+#include <fmt/core.h>
 
 #ifdef G_OS_WINDOWS
 #undef IN
 #undef OUT
 #endif
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gdSampleEditor::gdSampleEditor(ID channelId, m::Conf::Data& c)
-: gdWindow(c.sampleEditorX, c.sampleEditorY, c.sampleEditorW, c.sampleEditorH)
+: gdWindow(c.sampleEditorX, c.sampleEditorY, c.sampleEditorW, c.sampleEditorH, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TITLE))
 , m_channelId(channelId)
 , m_conf(c)
 {
@@ -116,8 +119,6 @@ void gdSampleEditor::rebuild()
 {
        m_data = c::sampleEditor::getData(m_channelId);
 
-       copy_label(m_data.name.c_str());
-
        waveTools->rebuild(m_data);
        volumeTool->rebuild(m_data);
        panTool->rebuild(m_data);
@@ -143,16 +144,16 @@ void gdSampleEditor::refresh()
 
 gePack* gdSampleEditor::createUpperBar()
 {
-       reload  = new geButton(0, 0, 70, G_GUI_UNIT, "Reload");
+       reload  = new geButton(0, 0, 70, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_RELOAD));
        grid    = new geChoice(0, 0, 50, G_GUI_UNIT);
-       snap    = new geCheck(0, 0, 12, G_GUI_UNIT, "Snap");
+       snap    = new geCheck(0, 0, 12, G_GUI_UNIT, g_ui.langMapper.get(LangMap::COMMON_SNAPTOGRID));
        sep1    = new geBox(0, 0, w() - 208, G_GUI_UNIT);
        zoomOut = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomOutOff_xpm, zoomOutOn_xpm);
        zoomIn  = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm);
 
        reload->callback(cb_reload, (void*)this);
 
-       grid->addItem("(off)");
+       grid->addItem("1");
        grid->addItem("2");
        grid->addItem("3");
        grid->addItem("4");
@@ -161,22 +162,22 @@ gePack* gdSampleEditor::createUpperBar()
        grid->addItem("16");
        grid->addItem("32");
        grid->addItem("64");
-       grid->copy_tooltip("Grid frequency");
+       grid->copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_GRIDRES));
        grid->showItem(m_conf.sampleEditorGridVal);
        grid->onChange = [this](ID) {
                waveTools->waveform->setGridLevel(std::stoi(grid->getSelectedLabel()));
        };
 
        snap->value(m_conf.sampleEditorGridOn);
-       snap->copy_tooltip("Snap to grid");
+       snap->copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_SNAPTOGRID));
        snap->callback(cb_enableSnap, (void*)this);
 
        /* TODO - redraw grid if != (off) */
 
        zoomOut->callback(cb_zoomOut, (void*)this);
-       zoomOut->copy_tooltip("Zoom out");
+       zoomOut->copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_ZOOMOUT));
        zoomIn->callback(cb_zoomIn, (void*)this);
-       zoomIn->copy_tooltip("Zoom in");
+       zoomIn->copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_ZOOMIN));
 
        gePack* g = new gePack(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, Direction::HORIZONTAL);
        g->add(reload);
@@ -216,7 +217,7 @@ geGroup* gdSampleEditor::createPreviewBox(int x, int y, int h)
 {
        rewind = new geButton(x, y + (h / 2) - 12, 25, 25, "", rewindOff_xpm, rewindOn_xpm);
        play   = new geStatusButton(rewind->x() + rewind->w() + 4, rewind->y(), 25, 25, play_xpm, pause_xpm);
-       loop   = new geCheck(play->x() + play->w() + 4, play->y(), 50, 25, "Loop");
+       loop   = new geCheck(play->x() + play->w() + 4, play->y(), 50, 25, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_LOOP));
 
        play->callback(cb_togglePreview, (void*)this);
        rewind->callback(cb_rewindPreview, (void*)this);
@@ -314,17 +315,9 @@ void gdSampleEditor::cb_zoomOut()
 
 void gdSampleEditor::updateInfo()
 {
-       std::string bitDepth = m_data.waveBits != 0 ? u::string::iToString(m_data.waveBits) : "(unknown)";
-       std::string infoText =
-           "File: " + m_data.wavePath + "\n"
-                                        "Size: " +
-           u::string::iToString(m_data.waveSize) + " frames\n"
-                                                   "Duration: " +
-           u::string::iToString(m_data.waveDuration) + " seconds\n"
-                                                       "Bit depth: " +
-           bitDepth + "\n"
-                      "Frequency: " +
-           u::string::iToString(m_data.waveRate) + " Hz\n";
+       std::string infoText = fmt::format(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_INFO),
+           m_data.wavePath, m_data.waveSize, m_data.waveDuration,
+           m_data.waveBits != 0 ? std::to_string(m_data.waveBits) : "?", m_data.waveRate);
 
        info->copy_label(infoText.c_str());
 }
index 48964fe28f7bd170c65dae23ef93156ade6a7f32..1c79f7b145efdc71195c997dbfa75299e718d935 100644 (file)
 #include "core/const.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "window.h"
 #include <FL/Fl.H>
 #include <FL/Fl_Window.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 namespace
@@ -46,11 +49,11 @@ bool confirmRet_ = false;
 
 void gdAlert(const char* msg)
 {
-       gdWindow win(u::gui::getCenterWinBounds(300, 90), "Alert");
+       gdWindow win(u::gui::getCenterWinBounds(300, 90), g_ui.langMapper.get(LangMap::COMMON_WARNING));
        win.set_modal();
        win.begin();
        geBox*    box = new geBox(10, 10, 280, 40, msg);
-       geButton* b   = new geButton(210, 60, 80, 20, "Close");
+       geButton* b   = new geButton(210, 60, 80, 20, g_ui.langMapper.get(LangMap::COMMON_CLOSE));
        win.end();
        box->labelsize(G_GUI_FONT_SIZE_BASE);
 
@@ -72,8 +75,8 @@ int gdConfirmWin(const char* title, const char* msg)
        win.set_modal();
        win.begin();
        new geBox(10, 10, 280, 40, msg);
-       geButton* ok = new geButton(212, 62, 80, 20, "Ok");
-       geButton* ko = new geButton(124, 62, 80, 20, "Cancel");
+       geButton* ok = new geButton(212, 62, 80, 20, g_ui.langMapper.get(LangMap::COMMON_OK));
+       geButton* ko = new geButton(124, 62, 80, 20, g_ui.langMapper.get(LangMap::COMMON_CANCEL));
        win.end();
 
        ok->shortcut(FL_Enter);
index 97ce87f7a3b89febf614d7d52da35b499da0d471..ac8150efe3e406189c779b84448b3b6ecf86962c 100644 (file)
 #include "core/conf.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/choice.h"
+#include "gui/ui.h"
 #include "utils/math.h"
 #include <FL/Fl_Double_Window.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geGridTool::geGridTool(Pixel x, Pixel y, m::Conf::Data& c)
@@ -58,8 +61,8 @@ geGridTool::geGridTool(Pixel x, Pixel y, m::Conf::Data& c)
 
        end();
 
-       gridType->copy_tooltip("Grid resolution");
-       active->copy_tooltip("Snap to grid");
+       gridType->copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_GRIDRES));
+       active->copy_tooltip(g_ui.langMapper.get(LangMap::COMMON_SNAPTOGRID));
 }
 
 /* -------------------------------------------------------------------------- */
index 16c6eab8e2cda8ab2c72afd4019f3f306145f99c..f58bcfdac9eb37c27dca4136993d53d0d90cd43a 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "sampleActionEditor.h"
+#include "gui/elems/actionEditor/sampleActionEditor.h"
 #include "core/const.h"
 #include "glue/actionEditor.h"
 #include "glue/channel.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
 #include "gui/dialogs/actionEditor/sampleActionEditor.h"
+#include "gui/ui.h"
 #include "sampleAction.h"
 #include "src/core/actions/action.h"
 #include "src/core/actions/actions.h"
@@ -38,6 +39,8 @@
 #include <FL/fl_draw.H>
 #include <cassert>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geSampleActionEditor::geSampleActionEditor(Pixel x, Pixel y, gdBaseActionEditor* b)
@@ -107,9 +110,9 @@ void geSampleActionEditor::draw()
        fl_color(G_COLOR_GREY_4);
        fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
        if (active())
-               fl_draw("start/stop", x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+               fl_draw(g_ui.langMapper.get(LangMap::ACTIONEDITOR_STARTSTOP), x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CENTER));
        else
-               fl_draw("start/stop (disabled)", x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+               fl_draw(g_ui.langMapper.get(LangMap::ACTIONEDITOR_STARTSTOPDISABLED), x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CENTER));
 
        draw_children();
 }
index 60e9033157dc29210af196c758898c3b9e0db7d7..efc1c7c83d089bb644d61001d970f57cfcaca633 100644 (file)
@@ -30,6 +30,7 @@
 #include "envelopePoint.h"
 #include "glue/actionEditor.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
+#include "gui/ui.h"
 #include "src/core/actions/action.h"
 #include "utils/log.h"
 #include "utils/math.h"
@@ -37,6 +38,8 @@
 #include <FL/fl_draw.H>
 #include <cassert>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geVelocityEditor::geVelocityEditor(Pixel x, Pixel y, gdBaseActionEditor* b)
@@ -57,7 +60,7 @@ void geVelocityEditor::draw()
 
        fl_color(G_COLOR_GREY_4);
        fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
-       fl_draw("Velocity", x() + 4, y(), w(), h(), FL_ALIGN_LEFT);
+       fl_draw(g_ui.langMapper.get(LangMap::ACTIONEDITOR_VELOCITY), x() + 4, y(), w(), h(), FL_ALIGN_LEFT);
 
        if (children() == 0)
                return;
index 8f4837c71f4627659908d7301dfe5804f295235a..3a26fe2ed8e44d20441289589a07f1b686c8b60f 100644 (file)
@@ -53,6 +53,13 @@ geScroll::geScroll(int x, int y, int w, int h, int t)
 
 /* -------------------------------------------------------------------------- */
 
+geScroll::geScroll(int type)
+: geScroll(0, 0, 0, 0, type)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
 void geScroll::cb_onScrollV(Fl_Widget* w, void* p)
 {
        geScroll*     s = static_cast<geScroll*>(w->parent());
index d13a8e827739947a06391883b781d57ef3b0815e..b9b8b894944c0b90fce07a4c3f59752457d1d3c6 100644 (file)
@@ -37,6 +37,7 @@ class geScroll : public Fl_Scroll
 {
 public:
        geScroll(int x, int y, int w, int h, int type = Fl_Scroll::BOTH);
+       geScroll(int type = Fl_Scroll::BOTH);
 
        int countChildren() const;
 
index ee6733eceec566d7ecbd992f8bdb752d1ae2d91b..8d2df7ce637a385357bbb95cd932b99eaea49e2f 100644 (file)
@@ -42,6 +42,15 @@ geStatusButton::geStatusButton(int x, int y, int w, int h, const char** imgOff,
 
 /* -------------------------------------------------------------------------- */
 
+geStatusButton::geStatusButton(const char** imgOff, const char** imgOn,
+    const char** imgDisabled)
+: geButton("", imgOff, imgOn, imgDisabled)
+, m_status(false)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
 void geStatusButton::draw()
 {
        if (active())
index 1c9a917cdcbb2079c9d95ae72913322661a5a4a1..c1d7e0ea08e91051685805c6f99845794173d3e7 100644 (file)
@@ -36,17 +36,20 @@ namespace giada::v
 {
 class geStatusButton : public geButton
 {
-  public:
+public:
        geStatusButton(int x, int y, int w, int h, const char** imgOff = nullptr,
            const char** imgOn = nullptr, const char** imgDisabled = nullptr);
 
+       geStatusButton(const char** imgOff = nullptr, const char** imgOn = nullptr,
+           const char** imgDisabled = nullptr);
+
        void draw() override;
 
        bool getStatus() const;
 
        void setStatus(bool s);
 
-  private:
+private:
        bool m_status;
 };
 } // namespace giada::v
diff --git a/src/gui/elems/config/stringMenu.cpp b/src/gui/elems/config/stringMenu.cpp
new file mode 100644 (file)
index 0000000..99e965a
--- /dev/null
@@ -0,0 +1,48 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "gui/elems/config/stringMenu.h"
+#include "utils/gui.h"
+
+namespace giada::v
+{
+geStringMenu::geStringMenu(const char* l, const std::vector<std::string>& data,
+    const std::string& msgIfNotFound, int labelWidth)
+: geChoice(l, labelWidth)
+{
+       if (data.size() == 0)
+       {
+               addItem(msgIfNotFound.c_str(), 0);
+               showItem(0);
+               deactivate();
+       }
+       else
+       {
+               for (const std::string& d : data)
+                       addItem(u::gui::removeFltkChars(d).c_str(), -1); // -1: auto-increment ID
+       }
+}
+} // namespace giada::v
\ No newline at end of file
diff --git a/src/gui/elems/config/stringMenu.h b/src/gui/elems/config/stringMenu.h
new file mode 100644 (file)
index 0000000..99de2ed
--- /dev/null
@@ -0,0 +1,44 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef GE_STRING_MENU_H
+#define GE_STRING_MENU_H
+
+#include "gui/elems/basics/choice.h"
+#include <string>
+#include <vector>
+
+namespace giada::v
+{
+class geStringMenu : public geChoice
+{
+public:
+       geStringMenu(const char* l, const std::vector<std::string>& data,
+           const std::string& msgIfNotFound, int labelWidth);
+};
+} // namespace giada::v
+
+#endif
index aaac8de49a7feef85524c60939d634dc44a866a7..ebe59805350071a715e1d3ea403e95217a3ef4b9 100644 (file)
 #include "gui/elems/basics/choice.h"
 #include "gui/elems/basics/flex.h"
 #include "gui/elems/basics/input.h"
+#include "gui/ui.h"
 #include "utils/string.h"
 #include <string>
 
 constexpr int LABEL_WIDTH = 110;
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geTabAudio::geDeviceMenu::geDeviceMenu(const char* l, const std::vector<c::config::AudioDeviceData>& devices)
@@ -45,7 +48,7 @@ geTabAudio::geDeviceMenu::geDeviceMenu(const char* l, const std::vector<c::confi
 {
        if (devices.size() == 0)
        {
-               addItem("-- no devices found --", 0);
+               addItem(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_NODEVICESFOUND), 0);
                showItem(0);
                return;
        }
@@ -88,7 +91,7 @@ void geTabAudio::geChannelMenu::rebuild(const c::config::AudioDeviceData& data)
 
        if (m_data.index == -1)
        {
-               addItem("none", 0);
+               addItem(g_ui.langMapper.get(LangMap::COMMON_NONE), 0);
                showItem(0);
                return;
        }
@@ -113,7 +116,7 @@ void geTabAudio::geChannelMenu::rebuild(const c::config::AudioDeviceData& data)
 /* -------------------------------------------------------------------------- */
 
 geTabAudio::geTabAudio(geompp::Rect<int> bounds)
-: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, "Audio")
+: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, g_ui.langMapper.get(LangMap::CONFIG_AUDIO_TITLE))
 , m_data(c::config::getAudioData())
 , m_initialApi(m_data.api)
 {
@@ -121,24 +124,24 @@ geTabAudio::geTabAudio(geompp::Rect<int> bounds)
 
        geFlex* body = new geFlex(bounds.reduced(G_GUI_OUTER_MARGIN), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
        {
-               soundsys = new geChoice("System", LABEL_WIDTH);
+               soundsys = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_SYSTEM), LABEL_WIDTH);
 
                geFlex* line1 = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       buffersize = new geChoice("Buffer size", LABEL_WIDTH);
-                       samplerate = new geChoice("Sample rate", LABEL_WIDTH);
+                       buffersize = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_BUFFERSIZE), LABEL_WIDTH);
+                       samplerate = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_SAMPLERATE), LABEL_WIDTH);
 
                        line1->add(buffersize, 180);
                        line1->add(samplerate, 180);
                        line1->end();
                }
 
-               sounddevOut = new geDeviceMenu("Output device", m_data.outputDevices);
+               sounddevOut = new geDeviceMenu(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_OUTPUTDEVICE), m_data.outputDevices);
 
                geFlex* line2 = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       channelsOut = new geChannelMenu("Output channels", m_data.outputDevice);
-                       limitOutput = new geCheck(x() + 177, y() + 93, 100, 20, "Limit output");
+                       channelsOut = new geChannelMenu(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_OUTPUTCHANNELS), m_data.outputDevice);
+                       limitOutput = new geCheck(x() + 177, y() + 93, 100, 20, g_ui.langMapper.get(LangMap::CONFIG_AUDIO_LIMITOUTPUT));
 
                        line2->add(channelsOut, 180);
                        line2->add(limitOutput);
@@ -147,7 +150,7 @@ geTabAudio::geTabAudio(geompp::Rect<int> bounds)
 
                geFlex* line3 = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       sounddevIn = new geDeviceMenu("Input device", m_data.inputDevices);
+                       sounddevIn = new geDeviceMenu(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_INPUTDEVICE), m_data.inputDevices);
                        enableIn   = new geCheck(0, 0, 0, 0);
 
                        line3->add(sounddevIn);
@@ -157,8 +160,8 @@ geTabAudio::geTabAudio(geompp::Rect<int> bounds)
 
                geFlex* line4 = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       channelsIn      = new geChannelMenu("Input channels", m_data.inputDevice);
-                       recTriggerLevel = new geInput(0, 0, 0, 0, "Rec threshold (dB)");
+                       channelsIn      = new geChannelMenu(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_INPUTCHANNELS), m_data.inputDevice);
+                       recTriggerLevel = new geInput(0, 0, 0, 0, g_ui.langMapper.get(LangMap::CONFIG_AUDIO_RECTHRESHOLD));
 
                        line4->add(channelsIn, 180);
                        line4->add(new geBox(), 132); // TODO - temporary hack for geInput's label
@@ -166,7 +169,7 @@ geTabAudio::geTabAudio(geompp::Rect<int> bounds)
                        line4->end();
                }
 
-               rsmpQuality = new geChoice("Resampling", LABEL_WIDTH);
+               rsmpQuality = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_RESAMPLING), LABEL_WIDTH);
 
                body->add(soundsys, 20);
                body->add(line1, 20);
@@ -175,7 +178,7 @@ geTabAudio::geTabAudio(geompp::Rect<int> bounds)
                body->add(line3, 20);
                body->add(line4, 20);
                body->add(rsmpQuality, 20);
-               body->add(new geBox("Restart Giada for the changes to take effect."));
+               body->add(new geBox(g_ui.langMapper.get(LangMap::CONFIG_RESTARTGIADA)));
                body->end();
        }
 
@@ -195,7 +198,7 @@ geTabAudio::geTabAudio(geompp::Rect<int> bounds)
        sounddevIn->showItem(m_data.inputDevice.index);
        sounddevIn->onChange = [this](ID id) { m_data.setInputDevice(id); fetch(); };
 
-       enableIn->copy_tooltip("Enable Input");
+       enableIn->copy_tooltip(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_ENABLEINPUT));
        enableIn->value(m_data.inputDevice.index != -1);
        enableIn->onChange = [this](bool b) { m_data.setInputDevice(b ? 0 : -1); fetch(); };
 
@@ -225,11 +228,11 @@ geTabAudio::geTabAudio(geompp::Rect<int> bounds)
        buffersize->showItem(m_data.bufferSize);
        buffersize->onChange = [this](ID id) { m_data.bufferSize = id; };
 
-       rsmpQuality->addItem("Sinc best quality (very slow)", 0);
-       rsmpQuality->addItem("Sinc medium quality (slow)", 1);
-       rsmpQuality->addItem("Sinc basic quality (medium)", 2);
-       rsmpQuality->addItem("Zero Order Hold (fast)", 3);
-       rsmpQuality->addItem("Linear (very fast)", 4);
+       rsmpQuality->addItem(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_RESAMPLING_SINCBEST), 0);
+       rsmpQuality->addItem(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_RESAMPLING_SINCMEDIUM), 1);
+       rsmpQuality->addItem(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_RESAMPLING_SINCBASIC), 2);
+       rsmpQuality->addItem(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_RESAMPLING_ZEROORDER), 3);
+       rsmpQuality->addItem(g_ui.langMapper.get(LangMap::CONFIG_AUDIO_RESAMPLING_LINEAR), 4);
        rsmpQuality->showItem(m_data.resampleQuality);
        rsmpQuality->onChange = [this](ID id) { m_data.resampleQuality = id; };
 
index bcf24941dce4f8ead5940a39378ad16a06662932..59782f223a400979ce9646ce2aec86ea6eb4cd59 100644 (file)
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/flex.h"
+#include "gui/ui.h"
 #include <FL/Fl_Pack.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geTabBehaviors::geTabBehaviors(geompp::Rect<int> bounds, m::Conf::Data& c)
-: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, "Behaviors")
+: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, g_ui.langMapper.get(LangMap::CONFIG_BEHAVIORS_TITLE))
 , m_conf(c)
 {
        end();
 
        geFlex* body = new geFlex(bounds.reduced(G_GUI_OUTER_MARGIN), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
        {
-               m_chansStopOnSeqHalt         = new geCheck(0, 0, 0, 0, "Dynamic channels stop immediately when the sequencer\nis halted");
-               m_treatRecsAsLoops           = new geCheck(0, 0, 0, 0, "Treat one shot channels with actions as loops");
-               m_inputMonitorDefaultOn      = new geCheck(0, 0, 0, 0, "New sample channels have input monitor on by default");
-               m_overdubProtectionDefaultOn = new geCheck(0, 0, 0, 0, "New sample channels have overdub protection on\nby default");
+               m_chansStopOnSeqHalt         = new geCheck(0, 0, 0, 0, g_ui.langMapper.get(LangMap::CONFIG_BEHAVIORS_CHANSSTOPONSEQHALT));
+               m_treatRecsAsLoops           = new geCheck(0, 0, 0, 0, g_ui.langMapper.get(LangMap::CONFIG_BEHAVIORS_TREATRECSASLOOPS));
+               m_inputMonitorDefaultOn      = new geCheck(0, 0, 0, 0, g_ui.langMapper.get(LangMap::CONFIG_BEHAVIORS_INPUTMONITORDEFAULTON));
+               m_overdubProtectionDefaultOn = new geCheck(0, 0, 0, 0, g_ui.langMapper.get(LangMap::CONFIG_BEHAVIORS_OVERDUBPROTECTIONDEFAULTON));
 
                body->add(m_chansStopOnSeqHalt, 30);
                body->add(m_treatRecsAsLoops, 20);
index 59c07b52b69a790c031e10865567a15126d47cec..ebf435273d56e7aa72b6f3cfd4b61a513c2ee72b 100644 (file)
 #include "core/const.h"
 #include "gui/elems/basics/liquidScroll.h"
 #include "gui/elems/keyBinder.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geTabBindings::geTabBindings(geompp::Rect<int> bounds, m::Conf::Data& conf)
-: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, "Key Bindings")
+: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, g_ui.langMapper.get(LangMap::CONFIG_BINDINGS_TITLE))
 {
        end();
 
        geFlex* body = new geFlex(bounds.reduced(G_GUI_OUTER_MARGIN), Direction::VERTICAL, G_GUI_INNER_MARGIN);
        {
-               play          = new geKeyBinder("Play", conf.keyBindings.find(m::Conf::KEY_BIND_PLAY)->second);
-               rewind        = new geKeyBinder("Rewind", conf.keyBindings.find(m::Conf::KEY_BIND_REWIND)->second);
-               recordActions = new geKeyBinder("Record actions", conf.keyBindings.find(m::Conf::KEY_BIND_RECORD_ACTIONS)->second);
-               recordInput   = new geKeyBinder("Record audio", conf.keyBindings.find(m::Conf::KEY_BIND_RECORD_INPUT)->second);
-               exit          = new geKeyBinder("Exit", conf.keyBindings.find(m::Conf::KEY_BIND_EXIT)->second);
+               play          = new geKeyBinder(g_ui.langMapper.get(LangMap::CONFIG_BINDINGS_PLAY), conf.keyBindings[m::Conf::KEY_BIND_PLAY]);
+               rewind        = new geKeyBinder(g_ui.langMapper.get(LangMap::CONFIG_BINDINGS_REWIND), conf.keyBindings[m::Conf::KEY_BIND_REWIND]);
+               recordActions = new geKeyBinder(g_ui.langMapper.get(LangMap::CONFIG_BINDINGS_RECORDACTIONS), conf.keyBindings[m::Conf::KEY_BIND_RECORD_ACTIONS]);
+               recordInput   = new geKeyBinder(g_ui.langMapper.get(LangMap::CONFIG_BINDINGS_RECORDAUDIO), conf.keyBindings[m::Conf::KEY_BIND_RECORD_INPUT]);
+               exit          = new geKeyBinder(g_ui.langMapper.get(LangMap::CONFIG_BINDINGS_EXIT), conf.keyBindings[m::Conf::KEY_BIND_EXIT]);
 
                body->add(play, G_GUI_UNIT);
                body->add(rewind, G_GUI_UNIT);
index c34e62863be2003724b9287d449b988348345c59..027effa0904e73fdb110a6c496b56419bced0e0a 100644 (file)
 #include "core/const.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/check.h"
+#include "gui/elems/basics/choice.h"
+#include "gui/elems/config/stringMenu.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include <string>
 
 constexpr int LABEL_WIDTH = 120;
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
-geTabMidi::geMenu::geMenu(const char* l, const std::vector<std::string>& data,
-    const std::string& msgIfNotFound)
-: geChoice(l, LABEL_WIDTH)
-{
-       if (data.size() == 0)
-       {
-               addItem(msgIfNotFound.c_str(), 0);
-               showItem(0);
-               deactivate();
-       }
-       else
-       {
-               for (const std::string& d : data)
-                       addItem(u::gui::removeFltkChars(d).c_str(), -1); // -1: auto-increment ID
-       }
-}
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
 geTabMidi::geTabMidi(geompp::Rect<int> bounds)
-: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, "MIDI")
+: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, g_ui.langMapper.get(LangMap::CONFIG_MIDI_TITLE))
 , m_data(c::config::getMidiData())
 , m_initialApi(m_data.api)
 {
@@ -65,11 +49,12 @@ geTabMidi::geTabMidi(geompp::Rect<int> bounds)
 
        geFlex* body = new geFlex(bounds.reduced(G_GUI_OUTER_MARGIN), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
        {
-               system = new geChoice("System", LABEL_WIDTH);
+               system = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_MIDI_SYSTEM), LABEL_WIDTH);
 
                geFlex* line1 = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       portOut   = new geMenu("Output port", m_data.outPorts, "-- no ports found --");
+                       portOut   = new geStringMenu(g_ui.langMapper.get(LangMap::CONFIG_MIDI_OUTPUTPORT),
+                m_data.outPorts, g_ui.langMapper.get(LangMap::CONFIG_MIDI_NOPORTSFOUND), LABEL_WIDTH);
                        enableOut = new geCheck(0, 0, 0, 0);
 
                        line1->add(portOut);
@@ -79,7 +64,8 @@ geTabMidi::geTabMidi(geompp::Rect<int> bounds)
 
                geFlex* line2 = new geFlex(Direction::HORIZONTAL, G_GUI_OUTER_MARGIN);
                {
-                       portIn   = new geMenu("Input port", m_data.inPorts, "-- no ports found --");
+                       portIn   = new geStringMenu(g_ui.langMapper.get(LangMap::CONFIG_MIDI_INPUTPORT),
+                m_data.inPorts, g_ui.langMapper.get(LangMap::CONFIG_MIDI_NOPORTSFOUND), LABEL_WIDTH);
                        enableIn = new geCheck(0, 0, 0, 0);
 
                        line2->add(portIn);
@@ -87,15 +73,16 @@ geTabMidi::geTabMidi(geompp::Rect<int> bounds)
                        line2->end();
                }
 
-               midiMap = new geMenu("Output Midi Map", m_data.midiMaps, "(no MIDI maps available)");
-               sync    = new geChoice("Sync", LABEL_WIDTH);
+               midiMap = new geStringMenu(g_ui.langMapper.get(LangMap::CONFIG_MIDI_OUTPUTMIDIMAP),
+                   m_data.midiMaps, g_ui.langMapper.get(LangMap::CONFIG_MIDI_NOMIDIMAPSFOUND), LABEL_WIDTH);
+               sync    = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_MIDI_SYNC), LABEL_WIDTH);
 
                body->add(system, 20);
                body->add(line1, 20);
                body->add(line2, 20);
                body->add(midiMap, 20);
                body->add(sync, 20);
-               body->add(new geBox("Restart Giada for the changes to take effect."));
+               body->add(new geBox(g_ui.langMapper.get(LangMap::CONFIG_RESTARTGIADA)));
                body->end();
        }
 
@@ -117,7 +104,7 @@ geTabMidi::geTabMidi(geompp::Rect<int> bounds)
        if (m_data.inPort == -1)
                portIn->deactivate();
 
-       enableOut->copy_tooltip("Enable Output port");
+       enableOut->copy_tooltip(g_ui.langMapper.get(LangMap::CONFIG_MIDI_LABEL_ENABLEOUT));
        enableOut->value(m_data.outPort != -1);
        enableOut->onChange = [this](bool b) {
                if (b)
@@ -132,7 +119,7 @@ geTabMidi::geTabMidi(geompp::Rect<int> bounds)
                }
        };
 
-       enableIn->copy_tooltip("Enable Input port");
+       enableIn->copy_tooltip(g_ui.langMapper.get(LangMap::CONFIG_MIDI_LABEL_ENABLEIN));
        enableIn->value(m_data.inPort != -1);
        enableIn->onChange = [this](bool b) {
                if (b)
index 3add0b5bb540fb23cea302ae20b3c0af3f02d3b5..07ece122123e24b45be9ae2a0ba601f81204fb1a 100644 (file)
 
 #include "deps/geompp/src/rect.hpp"
 #include "glue/config.h"
-#include "gui/elems/basics/choice.h"
 #include <FL/Fl_Group.H>
 
 class geCheck;
 
 namespace giada::v
 {
+class geStringMenu;
+class geChoice;
 class geTabMidi : public Fl_Group
 {
 public:
-       struct geMenu : public geChoice
-       {
-               geMenu(const char* l, const std::vector<std::string>&, const std::string& msgIfNotFound);
-       };
-
        geTabMidi(geompp::Rect<int>);
 
        void save() const;
 
-       geChoice* system;
-       geMenu*   portOut;
-       geMenu*   portIn;
-       geCheck*  enableOut;
-       geCheck*  enableIn;
-       geMenu*   midiMap;
-       geChoice* sync;
+       geChoice*     system;
+       geStringMenu* portOut;
+       geStringMenu* portIn;
+       geCheck*      enableOut;
+       geCheck*      enableIn;
+       geStringMenu* midiMap;
+       geChoice*     sync;
 
 private:
        void invalidate();
index 8cf108e82d75a7f3897596c65ecd3ed8fcd7900f..3f3a04b28f5d537d1586713e1b504b0ec43e7295 100644 (file)
 #include "tabMisc.h"
 #include "core/const.h"
 #include "gui/elems/basics/choice.h"
+#include "gui/elems/config/stringMenu.h"
+#include "gui/ui.h"
 
 constexpr int LABEL_WIDTH = 120;
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geTabMisc::geTabMisc(geompp::Rect<int> bounds)
-: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, "Misc")
+: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, g_ui.langMapper.get(LangMap::CONFIG_MISC_TITLE))
 , m_data(c::config::getMiscData())
 {
        end();
 
        geFlex* body = new geFlex(bounds.reduced(G_GUI_OUTER_MARGIN), Direction::VERTICAL, G_GUI_OUTER_MARGIN);
        {
-               m_debugMsg = new geChoice("Debug messages", LABEL_WIDTH);
-               m_tooltips = new geChoice("Tooltips", LABEL_WIDTH);
+               m_debugMsg = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_MISC_DEBUGMESSAGES), LABEL_WIDTH);
+               m_tooltips = new geChoice(g_ui.langMapper.get(LangMap::CONFIG_MISC_TOOLTIPS), LABEL_WIDTH);
+               m_langMap  = new geStringMenu(g_ui.langMapper.get(LangMap::CONFIG_MISC_LANGUAGE),
+            m_data.langMaps, g_ui.langMapper.get(LangMap::CONFIG_MISC_NOLANGUAGESFOUND), LABEL_WIDTH);
 
                body->add(m_debugMsg, 20);
                body->add(m_tooltips, 20);
+               body->add(m_langMap, 20);
                body->end();
        }
 
        add(body);
        resizable(body);
 
-       m_debugMsg->addItem("Disabled");
-       m_debugMsg->addItem("To standard output");
-       m_debugMsg->addItem("To file");
+       m_debugMsg->addItem(g_ui.langMapper.get(LangMap::CONFIG_MISC_DEBUGMESSAGES_DISABLED));
+       m_debugMsg->addItem(g_ui.langMapper.get(LangMap::CONFIG_MISC_DEBUGMESSAGES_TOSTDOUT));
+       m_debugMsg->addItem(g_ui.langMapper.get(LangMap::CONFIG_MISC_DEBUGMESSAGES_TOFILE));
        m_debugMsg->showItem(m_data.logMode);
        m_debugMsg->onChange = [this](ID id) { m_data.logMode = id; };
 
-       m_tooltips->addItem("Disabled");
-       m_tooltips->addItem("Enabled");
+       m_tooltips->addItem(g_ui.langMapper.get(LangMap::CONFIG_MISC_TOOLTIPS_DISABLED));
+       m_tooltips->addItem(g_ui.langMapper.get(LangMap::CONFIG_MISC_TOOLTIPS_ENABLED));
        m_tooltips->showItem(m_data.showTooltips);
        m_tooltips->onChange = [this](ID id) { m_data.showTooltips = id; };
+
+       m_langMap->addItem("English (default)");
+       if (m_data.langMap == "")
+               m_langMap->showItem(0);
+       else
+               m_langMap->showItem(m_data.langMap);
+       m_langMap->onChange = [this](ID /*id*/) { m_data.langMap = m_langMap->getSelectedLabel(); };
 }
 
 /* -------------------------------------------------------------------------- */
index f2d3c5a4664b5e3a5ea669581c0e4f225c51fd24..2d69edf6965ac1783d753cf1cb070e74979fb57b 100644 (file)
@@ -34,6 +34,7 @@
 namespace giada::v
 {
 class geChoice;
+class geStringMenu;
 class geTabMisc : public Fl_Group
 {
 public:
@@ -44,8 +45,9 @@ public:
 private:
        c::config::MiscData m_data;
 
-       geChoice* m_debugMsg;
-       geChoice* m_tooltips;
+       geChoice*     m_debugMsg;
+       geChoice*     m_tooltips;
+       geStringMenu* m_langMap;
 };
 } // namespace giada::v
 
index 43f5507dc1171dc3f4f1fa0cb19de986a5674c2f..c527f2534e0ac8e3b6760501e41b57092b81fd29 100644 (file)
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/flex.h"
 #include "gui/elems/basics/input.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <FL/Fl.H>
+#include <fmt/core.h>
 #include <functional>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geTabPlugins::geTabPlugins(geompp::Rect<int> bounds)
-: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, "Plug-ins")
+: Fl_Group(bounds.x, bounds.y, bounds.w, bounds.h, g_ui.langMapper.get(LangMap::CONFIG_PLUGINS_TITLE))
 {
        end();
 
@@ -77,7 +81,7 @@ geTabPlugins::geTabPlugins(geompp::Rect<int> bounds)
 
        m_info->hide();
 
-       m_folderPath->label("Plug-ins folder");
+       m_folderPath->label(g_ui.langMapper.get(LangMap::CONFIG_PLUGINS_FOLDER));
        m_folderPath->onChange = [this](const std::string& v) {
                m_data.pluginPath = v;
        };
@@ -88,7 +92,7 @@ geTabPlugins::geTabPlugins(geompp::Rect<int> bounds)
 
        m_scanButton->onClick = [this]() {
                std::function<void(float)> callback = [this](float progress) {
-                       std::string l = "Scan in progress (" + std::to_string((int)(progress * 100)) + "%). Please wait...";
+                       std::string l = fmt::format(g_ui.langMapper.get(LangMap::CONFIG_PLUGINS_SCANNING), static_cast<int>(progress * 100));
                        m_info->label(l.c_str());
                        Fl::wait();
                };
@@ -108,7 +112,7 @@ void geTabPlugins::rebuild()
 {
        m_data = c::config::getPluginData();
 
-       const std::string scanLabel = "Scan (" + std::to_string(m_data.numAvailablePlugins) + " found)";
+       const std::string scanLabel = fmt::format(g_ui.langMapper.get(LangMap::CONFIG_PLUGINS_SCAN), m_data.numAvailablePlugins);
        m_scanButton->copy_label(scanLabel.c_str());
 
        m_folderPath->value(m_data.pluginPath.c_str());
index db021e2c1f605b1f93e1530a3c1e75bda1b97a9e..cae48c45b66a320cc86ae8d35aef76e0a8198d35 100644 (file)
@@ -31,9 +31,7 @@
 #include "utils/fs.h"
 #include "utils/string.h"
 
-namespace giada
-{
-namespace v
+namespace giada::v
 {
 geFileBrowser::geFileBrowser(int x, int y, int w, int h)
 : Fl_File_Browser(x, y, w, h)
@@ -133,7 +131,7 @@ int geFileBrowser::handle(int e)
 
 std::string geFileBrowser::getCurrentDir()
 {
-       return normalize(u::fs::getRealPath(m_currentDir));
+       return u::fs::getRealPath(m_currentDir);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -141,18 +139,11 @@ std::string geFileBrowser::getCurrentDir()
 std::string geFileBrowser::getSelectedItem(bool fullPath)
 {
        if (!fullPath) // no full path requested? return the selected text
-               return normalize(text(value()));
+               return text(value());
        else if (value() == 0) // no rows selected? return current directory
-               return normalize(m_currentDir);
+               return m_currentDir;
        else
-       {
-#ifdef G_OS_WINDOWS
-               std::string sep = m_currentDir != "" ? G_SLASH_STR : "";
-#else
-               std::string sep = G_SLASH_STR;
-#endif
-               return normalize(u::fs::getRealPath(m_currentDir + sep + normalize(text(value()))));
-       }
+               return u::fs::getRealPath(u::fs::join(m_currentDir, text(value())));
 }
 
 /* -------------------------------------------------------------------------- */
@@ -162,20 +153,4 @@ void geFileBrowser::preselect(int pos, int line)
        position(pos);
        select(line);
 }
-
-/* -------------------------------------------------------------------------- */
-
-std::string geFileBrowser::normalize(const std::string& s)
-{
-       std::string out = s;
-
-       /* If std::string ends with G_SLASH, remove it. Don't do it if is the root dir, 
-       that is '/' on Unix or '[x]:\' on Windows. */
-
-       //if (out.back() == G_SLASH && out.length() > 1)
-       if (out.back() == G_SLASH && !u::fs::isRootDir(s))
-               out = out.substr(0, out.size() - 1);
-       return out;
-}
-} // namespace v
-} // namespace giada
\ No newline at end of file
+} // namespace giada::v
\ No newline at end of file
index 624a86a7a58cf3f007c980195b9fe7b8a22e7550..c11696b51628e3934f0632d282d8545b492ac812 100644 (file)
@@ -32,9 +32,7 @@
 #include <FL/Fl_File_Browser.H>
 #include <string>
 
-namespace giada
-{
-namespace v
+namespace giada::v
 {
 class geFileBrowser : public Fl_File_Browser
 {
@@ -60,16 +58,10 @@ public:
 
        int handle(int e);
 
-  private:
-       /* normalize
-       Makes sure the std::string never ends with a trailing slash. */
-
-       std::string normalize(const std::string& s);
-
+private:
        std::string m_currentDir;
        bool        m_showHiddenFiles;
 };
-} // namespace v
-} // namespace giada
+} // namespace giada::v
 
 #endif
index 93d2c3f5b97bcacab4067e7a2bf8eb71b5425c6c..8ae73536e04aeb0e05b9af477423ef1a7a9952d9 100644 (file)
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geKeyBinder::geKeyBinder(const std::string& l, int& keyRef)
@@ -40,8 +43,8 @@ geKeyBinder::geKeyBinder(const std::string& l, int& keyRef)
 {
        m_labelBox = new geBox(l.c_str());
        m_keyBox   = new geBox(u::gui::keyToString(keyRef).c_str());
-       m_bindBtn  = new geButton("Bind");
-       m_clearBtn = new geButton("Clear");
+       m_bindBtn  = new geButton(g_ui.langMapper.get(LangMap::COMMON_BIND));
+       m_clearBtn = new geButton(g_ui.langMapper.get(LangMap::COMMON_CLEAR));
 
        add(m_labelBox);
        add(m_keyBox, 100);
index 237ac6178ca1b0ec717f2ff969a381530167d6e0..f6a00a5f7b4d426dfa33b92b23b4d08135c4baaf 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-#include "column.h"
+#include "gui/elems/mainWindow/keyboard/column.h"
 #include "core/model/model.h"
 #include "glue/channel.h"
 #include "gui/dialogs/warnings.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/resizerBar.h"
-#include "keyboard.h"
-#include "midiChannel.h"
-#include "sampleChannel.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
+#include "gui/elems/mainWindow/keyboard/midiChannel.h"
+#include "gui/elems/mainWindow/keyboard/sampleChannel.h"
+#include "gui/ui.h"
 #include "utils/fs.h"
 #include "utils/gui.h"
 #include "utils/log.h"
 #include <FL/fl_draw.H>
 #include <cassert>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
+namespace
+{
+enum class Menu
+{
+       ADD_SAMPLE_CHANNEL = 0,
+       ADD_MIDI_CHANNEL,
+       REMOVE
+};
+
+void MenuCallback(Fl_Widget* w, void* v)
+{
+       const geColumn* column = static_cast<geColumn*>(w);
+
+       switch ((Menu)(intptr_t)v)
+       {
+       case Menu::ADD_SAMPLE_CHANNEL:
+               c::channel::addChannel(column->id, ChannelType::SAMPLE);
+               break;
+       case Menu::ADD_MIDI_CHANNEL:
+               c::channel::addChannel(column->id, ChannelType::MIDI);
+               break;
+       case Menu::REMOVE:
+               static_cast<geKeyboard*>(column->parent())->deleteColumn(column->id);
+               break;
+       }
+}
+} // namespace
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
 geColumn::geColumn(int X, int Y, int W, int H, ID id, geResizerBar* b)
 : Fl_Group(X, Y, W, H)
 , id(id)
@@ -114,16 +149,16 @@ geChannel* geColumn::addChannel(c::channel::Data d)
 
 void geColumn::cb_addChannel()
 {
-       u::log::print("[geColumn::cb_addChannel] id = %d\n", id);
+       G_DEBUG("Column id: " << id);
 
        Fl_Menu_Item menu[] = {
-           u::gui::makeMenuItem("Add Sample channel"),
-           u::gui::makeMenuItem("Add MIDI channel"),
-           u::gui::makeMenuItem("Remove"),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_COLUMN_BUTTON_ADDSAMPLECHANNEL), MenuCallback, (void*)Menu::ADD_SAMPLE_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_COLUMN_BUTTON_ADDMIDICHANNEL), MenuCallback, (void*)Menu::ADD_MIDI_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_COLUMN_BUTTON_REMOVE), MenuCallback, (void*)Menu::REMOVE),
            {}};
 
        if (countChannels() > 0)
-               menu[2].deactivate();
+               menu[(int)Menu::REMOVE].deactivate();
 
        Fl_Menu_Button b(0, 0, 100, 50);
        b.box(G_CUSTOM_BORDER_BOX);
@@ -132,15 +167,8 @@ void geColumn::cb_addChannel()
        b.color(G_COLOR_GREY_2);
 
        const Fl_Menu_Item* m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, &b);
-       if (m == nullptr)
-               return;
-
-       if (strcmp(m->label(), "Add Sample channel") == 0)
-               c::channel::addChannel(id, ChannelType::SAMPLE);
-       else if (strcmp(m->label(), "Add MIDI channel") == 0)
-               c::channel::addChannel(id, ChannelType::MIDI);
-       else
-               static_cast<geKeyboard*>(parent())->deleteColumn(id);
+       if (m != nullptr)
+               m->do_callback(this, m->user_data());
 }
 
 /* -------------------------------------------------------------------------- */
@@ -160,7 +188,7 @@ void geColumn::init()
        Fl_Group::clear();
        m_channels.clear();
 
-       m_addChannelBtn = new geButton(x(), y(), w(), G_GUI_UNIT, "Edit column");
+       m_addChannelBtn = new geButton(x(), y(), w(), G_GUI_UNIT, g_ui.langMapper.get(LangMap::MAIN_COLUMN_BUTTON));
        m_addChannelBtn->callback(cb_addChannel, (void*)this);
 
        add(m_addChannelBtn);
index 4c72ca3f9c634ce2f8f2375783f10b79f29ced33..aad98d50cf85cebae612423b8e156fd32843e4cd 100644 (file)
@@ -48,8 +48,8 @@ extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
-geKeyboard::geKeyboard(int X, int Y, int W, int H)
-: geScroll(X, Y, W, H, Fl_Scroll::BOTH_ALWAYS)
+geKeyboard::geKeyboard()
+: geScroll(Fl_Scroll::BOTH_ALWAYS)
 , m_addColumnBtn(nullptr)
 {
        end();
index c5593f8d4097da5e3098fc1daa3f716756a8abc9..178b650813281a91c1b41b312fb4b752541a33d2 100644 (file)
@@ -48,7 +48,7 @@ public:
                int width;
        };
 
-       geKeyboard(int X, int Y, int W, int H);
+       geKeyboard();
 
        int  handle(int e) override;
        void draw() override;
index 4ced13c83574d23829973fd20a7de9d7b913787e..1031f14b59b0656c992e04fc3f745413fa015018 100644 (file)
 #include "gui/elems/mainWindow/keyboard/midiActivity.h"
 #include "core/const.h"
 #include "gui/elems/basics/flex.h"
+#include "gui/ui.h"
 #include <FL/fl_draw.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geMidiActivity::geLed::geLed()
@@ -85,7 +88,6 @@ geMidiActivity::geMidiActivity(int x, int y, int w, int h)
        add(container);
        resizable(container);
 
-       copy_tooltip("MIDI I/O activity\n\nNotifies MIDI messages sent (top) or "
-                    "received (bottom) by this channel.");
+       copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_MIDIACTIVITY));
 }
 } // namespace giada::v
\ No newline at end of file
index 3273c855587c7e44f68b86fee9e86a4ce0a5a374..d5e449d3862e84af8d81ca098be4e053490d44ca 100644 (file)
 #include "gui/elems/mainWindow/keyboard/column.h"
 #include "gui/elems/mainWindow/keyboard/midiActivity.h"
 #include "gui/elems/mainWindow/keyboard/midiChannelButton.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <FL/Fl_Menu_Button.H>
 #include <cassert>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 namespace
@@ -128,14 +131,14 @@ geMidiChannel::geMidiChannel(int X, int Y, int W, int H, c::channel::Data d)
 
        resizable(mainButton);
 
-       playButton->copy_tooltip("Play/stop");
-       arm->copy_tooltip("Arm for recording");
-       mute->copy_tooltip("Mute");
-       solo->copy_tooltip("Solo");
+       playButton->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_PLAY));
+       arm->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_ARM));
+       mute->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_MUTE));
+       solo->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_SOLO));
 #if defined(WITH_VST)
-       fx->copy_tooltip("Plug-ins");
+       fx->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_FX));
 #endif
-       vol->copy_tooltip("Volume");
+       vol->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_VOLUME));
 
 #ifdef WITH_VST
        fx->setStatus(m_channel.plugins.size() > 0);
@@ -183,16 +186,16 @@ void geMidiChannel::cb_playButton()
 void geMidiChannel::cb_openMenu()
 {
        Fl_Menu_Item rclick_menu[] = {
-           u::gui::makeMenuItem("Edit actions...", menuCallback, (void*)Menu::EDIT_ACTIONS),
-           u::gui::makeMenuItem("Clear actions", menuCallback, (void*)Menu::CLEAR_ACTIONS, FL_SUBMENU),
-           u::gui::makeMenuItem("All", menuCallback, (void*)Menu::CLEAR_ACTIONS_ALL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_EDITACTIONS), menuCallback, (void*)Menu::EDIT_ACTIONS),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLEARACTIONS), menuCallback, (void*)Menu::CLEAR_ACTIONS, FL_SUBMENU),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLEARACTIONS_ALL), menuCallback, (void*)Menu::CLEAR_ACTIONS_ALL),
            {},
-           u::gui::makeMenuItem("Setup keyboard input...", menuCallback, (void*)Menu::SETUP_KEYBOARD_INPUT),
-           u::gui::makeMenuItem("Setup MIDI input...", menuCallback, (void*)Menu::SETUP_MIDI_INPUT),
-           u::gui::makeMenuItem("Setup MIDI output...", menuCallback, (void*)Menu::SETUP_MIDI_OUTPUT),
-           u::gui::makeMenuItem("Rename", menuCallback, (void*)Menu::RENAME_CHANNEL),
-           u::gui::makeMenuItem("Clone", menuCallback, (void*)Menu::CLONE_CHANNEL),
-           u::gui::makeMenuItem("Delete", menuCallback, (void*)Menu::DELETE_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_KEYBOARDINPUT), menuCallback, (void*)Menu::SETUP_KEYBOARD_INPUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_MIDIINPUT), menuCallback, (void*)Menu::SETUP_MIDI_INPUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_MIDIOUTPUT), menuCallback, (void*)Menu::SETUP_MIDI_OUTPUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_RENAME), menuCallback, (void*)Menu::RENAME_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLONE), menuCallback, (void*)Menu::CLONE_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_DELETE), menuCallback, (void*)Menu::DELETE_CHANNEL),
            {}};
 
        /* No 'clear actions' if there are no actions. */
index f2759e46417f1bc6180981a7d361e77ba8a3cb1a..1ff1921a8ed71a9029c3a64f9c365b7b64734d12 100644 (file)
 #include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/keyboard/midiActivity.h"
 #include "gui/elems/mainWindow/keyboard/sampleChannelButton.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 namespace
@@ -196,18 +199,17 @@ geSampleChannel::geSampleChannel(int X, int Y, int W, int H, c::channel::Data d)
 
        resizable(mainButton);
 
-       playButton->copy_tooltip("Play/stop");
-       arm->copy_tooltip("Arm for recording");
-       status->copy_tooltip("Progress bar");
-       readActions->copy_tooltip("Read actions\n\nToggles playback of pre-recorded "
-                                 "actions (key press, key release, ...).");
-       modeBox->copy_tooltip("Mode");
-       mute->copy_tooltip("Mute");
-       solo->copy_tooltip("Solo");
+       playButton->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_PLAY));
+       arm->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_ARM));
+       status->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_STATUS));
+       readActions->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_READACTIONS));
+       modeBox->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_MODEBOX));
+       mute->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_MUTE));
+       solo->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_SOLO));
 #if defined(WITH_VST)
-       fx->copy_tooltip("Plug-ins");
+       fx->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_FX));
 #endif
-       vol->copy_tooltip("Volume");
+       vol->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_LABEL_VOLUME));
 
 #ifdef WITH_VST
        fx->setStatus(m_channel.plugins.size() > 0);
@@ -264,26 +266,26 @@ void geSampleChannel::cb_openMenu()
                return;
 
        Fl_Menu_Item rclick_menu[] = {
-           u::gui::makeMenuItem("Input monitor", menuCallback, (void*)Menu::INPUT_MONITOR,
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_INPUTMONITOR), menuCallback, (void*)Menu::INPUT_MONITOR,
                FL_MENU_TOGGLE | (m_channel.sample->getInputMonitor() ? FL_MENU_VALUE : 0)),
-           u::gui::makeMenuItem("Overdub protection", menuCallback, (void*)Menu::OVERDUB_PROTECTION,
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_OVERDUBPROTECTION), menuCallback, (void*)Menu::OVERDUB_PROTECTION,
                FL_MENU_TOGGLE | FL_MENU_DIVIDER | (m_channel.sample->getOverdubProtection() ? FL_MENU_VALUE : 0)),
-           u::gui::makeMenuItem("Load new sample...", menuCallback, (void*)Menu::LOAD_SAMPLE),
-           u::gui::makeMenuItem("Export sample to file...", menuCallback, (void*)Menu::EXPORT_SAMPLE),
-           u::gui::makeMenuItem("Setup keyboard input...", menuCallback, (void*)Menu::SETUP_KEYBOARD_INPUT),
-           u::gui::makeMenuItem("Setup MIDI input...", menuCallback, (void*)Menu::SETUP_MIDI_INPUT),
-           u::gui::makeMenuItem("Setup MIDI output...", menuCallback, (void*)Menu::SETUP_MIDI_OUTPUT),
-           u::gui::makeMenuItem("Edit sample...", menuCallback, (void*)Menu::EDIT_SAMPLE),
-           u::gui::makeMenuItem("Edit actions...", menuCallback, (void*)Menu::EDIT_ACTIONS),
-           u::gui::makeMenuItem("Clear actions", menuCallback, (void*)Menu::CLEAR_ACTIONS, FL_SUBMENU),
-           u::gui::makeMenuItem("All", menuCallback, (void*)Menu::CLEAR_ACTIONS_ALL),
-           u::gui::makeMenuItem("Volume", menuCallback, (void*)Menu::CLEAR_ACTIONS_VOLUME),
-           u::gui::makeMenuItem("Start/Stop", menuCallback, (void*)Menu::CLEAR_ACTIONS_START_STOP),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_LOADSAMPLE), menuCallback, (void*)Menu::LOAD_SAMPLE),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_EXPORTSAMPLE), menuCallback, (void*)Menu::EXPORT_SAMPLE),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_KEYBOARDINPUT), menuCallback, (void*)Menu::SETUP_KEYBOARD_INPUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_MIDIINPUT), menuCallback, (void*)Menu::SETUP_MIDI_INPUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_MIDIOUTPUT), menuCallback, (void*)Menu::SETUP_MIDI_OUTPUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_EDITSAMPLE), menuCallback, (void*)Menu::EDIT_SAMPLE),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_EDITACTIONS), menuCallback, (void*)Menu::EDIT_ACTIONS),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLEARACTIONS), menuCallback, (void*)Menu::CLEAR_ACTIONS, FL_SUBMENU),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLEARACTIONS_ALL), menuCallback, (void*)Menu::CLEAR_ACTIONS_ALL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLEARACTIONS_VOLUME), menuCallback, (void*)Menu::CLEAR_ACTIONS_VOLUME),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLEARACTIONS_STARTSTOP), menuCallback, (void*)Menu::CLEAR_ACTIONS_START_STOP),
            {},
-           u::gui::makeMenuItem("Rename", menuCallback, (void*)Menu::RENAME_CHANNEL),
-           u::gui::makeMenuItem("Clone", menuCallback, (void*)Menu::CLONE_CHANNEL),
-           u::gui::makeMenuItem("Free", menuCallback, (void*)Menu::FREE_CHANNEL),
-           u::gui::makeMenuItem("Delete", menuCallback, (void*)Menu::DELETE_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_RENAME), menuCallback, (void*)Menu::RENAME_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_CLONE), menuCallback, (void*)Menu::CLONE_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_FREE), menuCallback, (void*)Menu::FREE_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_MENU_DELETE), menuCallback, (void*)Menu::DELETE_CHANNEL),
            {}};
 
        if (m_channel.sample->waveId == 0)
index e319ac3c166b9a77da2bdca37a2d34d9010a58ad..d98974268690bc520008b2b4bea6fa9fba38a2fe 100644 (file)
 #include "sampleChannelButton.h"
 #include "glue/channel.h"
 #include "gui/dialogs/mainWindow.h"
+#include "gui/ui.h"
 #include "keyboard.h"
 #include "sampleChannel.h"
 #include "utils/fs.h"
 #include "utils/string.h"
 #include <FL/Fl.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h, const c::channel::Data& d)
@@ -42,10 +45,10 @@ geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h, const c
        {
        case ChannelStatus::MISSING:
        case ChannelStatus::WRONG:
-               label("* file not found! *");
+               label(g_ui.langMapper.get(LangMap::MAIN_CHANNEL_SAMPLENOTFOUND));
                break;
        default:
-               label(m_channel.sample->waveId == 0 ? "-- no sample --" : m_channel.name.c_str());
+               label(m_channel.sample->waveId == 0 ? g_ui.langMapper.get(LangMap::MAIN_CHANNEL_NOSAMPLE) : m_channel.name.c_str());
                break;
        }
 }
index 8b3fca89b6139b79de418b98963b8fe8a89fa4dd..e1783deabc2c424c3acded1bd90c7f6f11080741 100644 (file)
 #include "gui/elems/basics/dial.h"
 #include "gui/elems/basics/statusButton.h"
 #include "gui/elems/soundMeter.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #ifdef WITH_VST
 #include "gui/elems/basics/statusButton.h"
 #endif
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
-geMainIO::geMainIO(int x, int y, int w, int h)
-: geFlex(x, y, w, h, Direction::HORIZONTAL, G_GUI_INNER_MARGIN)
+geMainIO::geMainIO()
+: geFlex(Direction::HORIZONTAL, G_GUI_INNER_MARGIN)
 {
        m_outMeter = new geSoundMeter(0, 0, 0, 0);
        m_inMeter  = new geSoundMeter(0, 0, 0, 0);
@@ -68,14 +71,14 @@ geMainIO::geMainIO(int x, int y, int w, int h)
 #endif
        end();
 
-       m_outMeter->copy_tooltip("Main output meter");
-       m_inMeter->copy_tooltip("Main input meter");
-       m_outVol->copy_tooltip("Main output volume");
-       m_inVol->copy_tooltip("Main input volume");
-       m_inToOut->copy_tooltip("Stream linker\n\nConnects input to output to enable \"hear what you're playing\" mode.");
+       m_outMeter->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_IO_LABEL_OUTMETER));
+       m_inMeter->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_IO_LABEL_INMETER));
+       m_outVol->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_IO_LABEL_OUTVOL));
+       m_inVol->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_IO_LABEL_INVOL));
+       m_inToOut->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_IO_LABEL_INTOOUT));
 #ifdef WITH_VST
-       m_masterFxOut->copy_tooltip("Main output plug-ins");
-       m_masterFxIn->copy_tooltip("Main input plug-ins");
+       m_masterFxOut->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_IO_LABEL_FXOUT));
+       m_masterFxIn->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_IO_LABEL_FXIN));
 #endif
 
        m_outVol->onChange = [](float v) {
@@ -87,8 +90,8 @@ geMainIO::geMainIO(int x, int y, int w, int h)
        };
 
        m_inToOut->type(FL_TOGGLE_BUTTON);
-       m_inToOut->onClick = [v = m_inToOut->value()]() {
-               c::main::setInToOut(v);
+       m_inToOut->onClick = [&inToOut = m_inToOut]() {
+               c::main::setInToOut(inToOut->value());
        };
 
 #ifdef WITH_VST
index 9b83ccc9337aceaa9490977cd5c18b83887c9173..fecb390959f7d766f6b66a69c5cdc297d5e268bf 100644 (file)
@@ -39,7 +39,7 @@ class geStatusButton;
 class geMainIO : public geFlex
 {
 public:
-       geMainIO(int x, int y, int w, int h);
+       geMainIO();
 
        void refresh();
        void rebuild();
index 082331326ab923f87550e9b6917ae1c20d9e66f0..dece25c9551271041ff07af3e9ed77a3d73cd3e8 100644 (file)
 #include "glue/main.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
+#include "gui/ui.h"
 #include "keyboard/keyboard.h"
 #include "utils/gui.h"
 #include <FL/Fl_Menu_Button.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
-geMainMenu::geMainMenu(int x, int y)
-: gePack(x, y, Direction::HORIZONTAL, G_GUI_INNER_MARGIN)
+namespace
+{
+enum class FileMenu
+{
+       OPEN_PROJECT = 0,
+       SAVE_PROJECT,
+       CLOSE_PROJECT,
+#ifdef G_DEBUG_MODE
+       DEBUG_STATS,
+#endif
+       QUIT
+};
+
+void fileMenuCallback(Fl_Widget* /*w*/, void* v)
+{
+       switch ((FileMenu)(intptr_t)v)
+       {
+       case FileMenu::OPEN_PROJECT:
+               c::layout::openBrowserForProjectLoad();
+               break;
+       case FileMenu::SAVE_PROJECT:
+               c::layout::openBrowserForProjectSave();
+               break;
+       case FileMenu::CLOSE_PROJECT:
+               c::main::closeProject();
+               break;
+#ifdef G_DEBUG_MODE
+       case FileMenu::DEBUG_STATS:
+               c::main::printDebugInfo();
+               break;
+#endif
+       case FileMenu::QUIT:
+               c::main::quitGiada();
+               break;
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+enum class EditMenu
+{
+       FREE_SAMPLE_CHANNELS = 0,
+       CLEAR_ALL_ACTIONS,
+       SETUP_MIDI_INPUT
+};
+
+void editMenuCallback(Fl_Widget* /*w*/, void* v)
 {
-       geButton* file   = new geButton(0, 0, 70, G_GUI_UNIT, "File");
-       geButton* edit   = new geButton(0, 0, 70, G_GUI_UNIT, "Edit");
-       geButton* config = new geButton(0, 0, 70, G_GUI_UNIT, "Config");
-       geButton* about  = new geButton(0, 0, 70, G_GUI_UNIT, "About");
-       add(file);
-       add(edit);
-       add(config);
-       add(about);
+       switch ((EditMenu)(intptr_t)v)
+       {
+       case EditMenu::FREE_SAMPLE_CHANNELS:
+               c::main::clearAllSamples();
+               break;
+       case EditMenu::CLEAR_ALL_ACTIONS:
+               c::main::clearAllActions();
+               break;
+       case EditMenu::SETUP_MIDI_INPUT:
+               c::layout::openMasterMidiInputWindow();
+               break;
+       }
+}
+} // namespace
 
-       resizable(nullptr);
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+geMainMenu::geMainMenu()
+: geFlex(Direction::HORIZONTAL, G_GUI_INNER_MARGIN)
+{
+       geButton* file   = new geButton(g_ui.langMapper.get(LangMap::MAIN_MENU_FILE));
+       geButton* edit   = new geButton(g_ui.langMapper.get(LangMap::MAIN_MENU_EDIT));
+       geButton* config = new geButton(g_ui.langMapper.get(LangMap::MAIN_MENU_CONFIG));
+       geButton* about  = new geButton(g_ui.langMapper.get(LangMap::MAIN_MENU_ABOUT));
+       add(file, 80);
+       add(edit, 80);
+       add(config, 80);
+       add(about, 80);
+       end();
 
        file->onClick   = [this]() { cb_file(); };
        edit->onClick   = [this]() { cb_edit(); };
@@ -62,13 +131,13 @@ geMainMenu::geMainMenu(int x, int y)
 void geMainMenu::cb_file()
 {
        Fl_Menu_Item menu[] = {
-           u::gui::makeMenuItem("Open project..."),
-           u::gui::makeMenuItem("Save project..."),
-           u::gui::makeMenuItem("Close project"),
-#ifndef NDEBUG
-           u::gui::makeMenuItem("Debug stats"),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_MENU_FILE_OPENPROJECT), fileMenuCallback, (void*)FileMenu::OPEN_PROJECT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_MENU_FILE_SAVEPROJECT), fileMenuCallback, (void*)FileMenu::SAVE_PROJECT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_MENU_FILE_CLOSEPROJECT), fileMenuCallback, (void*)FileMenu::CLOSE_PROJECT),
+#ifdef G_DEBUG_MODE
+           u::gui::makeMenuItem("Debug stats", fileMenuCallback, (void*)FileMenu::DEBUG_STATS),
 #endif
-           u::gui::makeMenuItem("Quit Giada"),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_MENU_FILE_QUIT), fileMenuCallback, (void*)FileMenu::QUIT),
            {}};
 
        Fl_Menu_Button b(0, 0, 100, 50);
@@ -78,31 +147,8 @@ void geMainMenu::cb_file()
        b.color(G_COLOR_GREY_2);
 
        const Fl_Menu_Item* m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, &b);
-       if (!m)
-               return;
-
-       if (strcmp(m->label(), "Open project...") == 0)
-       {
-               c::layout::openBrowserForProjectLoad();
-       }
-       else if (strcmp(m->label(), "Save project...") == 0)
-       {
-               c::layout::openBrowserForProjectSave();
-       }
-       else if (strcmp(m->label(), "Close project") == 0)
-       {
-               c::main::closeProject();
-       }
-#ifdef G_DEBUG_MODE
-       else if (strcmp(m->label(), "Debug stats") == 0)
-       {
-               c::main::printDebugInfo();
-       }
-#endif
-       else if (strcmp(m->label(), "Quit Giada") == 0)
-       {
-               c::main::quitGiada();
-       }
+       if (m != nullptr)
+               m->do_callback(this, m->user_data());
 }
 
 /* -------------------------------------------------------------------------- */
@@ -112,18 +158,18 @@ void geMainMenu::cb_edit()
        c::main::MainMenu menu = c::main::getMainMenu();
 
        Fl_Menu_Item menuItem[] = {
-           u::gui::makeMenuItem("Free all Sample channels"),
-           u::gui::makeMenuItem("Clear all actions"),
-           u::gui::makeMenuItem("Setup global MIDI input..."),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_MENU_EDIT_FREEALLSAMPLES), editMenuCallback, (void*)EditMenu::FREE_SAMPLE_CHANNELS),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_MENU_EDIT_CLEARALLACTIONS), editMenuCallback, (void*)EditMenu::CLEAR_ALL_ACTIONS),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::MAIN_MENU_EDIT_SETUPMIDIINPUT), editMenuCallback, (void*)EditMenu::SETUP_MIDI_INPUT),
            {}};
 
-       menuItem[0].deactivate();
-       menuItem[1].deactivate();
+       menuItem[(int)EditMenu::FREE_SAMPLE_CHANNELS].deactivate();
+       menuItem[(int)EditMenu::CLEAR_ALL_ACTIONS].deactivate();
 
        if (menu.hasAudioData)
-               menuItem[0].activate();
+               menuItem[(int)EditMenu::FREE_SAMPLE_CHANNELS].activate();
        if (menu.hasActions)
-               menuItem[1].activate();
+               menuItem[(int)EditMenu::CLEAR_ALL_ACTIONS].activate();
 
        Fl_Menu_Button b(0, 0, 100, 50);
        b.box(G_CUSTOM_BORDER_BOX);
@@ -132,14 +178,7 @@ void geMainMenu::cb_edit()
        b.color(G_COLOR_GREY_2);
 
        const Fl_Menu_Item* m = menuItem->popup(Fl::event_x(), Fl::event_y(), 0, 0, &b);
-       if (!m)
-               return;
-
-       if (strcmp(m->label(), "Free all Sample channels") == 0)
-               c::main::clearAllSamples();
-       else if (strcmp(m->label(), "Clear all actions") == 0)
-               c::main::clearAllActions();
-       else if (strcmp(m->label(), "Setup global MIDI input...") == 0)
-               c::layout::openMasterMidiInputWindow();
+       if (m != nullptr)
+               m->do_callback(this, m->user_data());
 }
-} // namespace giada::v
+} // namespace giada::v
\ No newline at end of file
index 4ca3823eb195f4aa36f21444526f9ef1795214ef..9b16d0c55bc2cbfe4992d4e73378727ee445acbc 100644 (file)
 #ifndef GE_MAIN_MENU_H
 #define GE_MAIN_MENU_H
 
-#include "gui/elems/basics/pack.h"
+#include "gui/elems/basics/flex.h"
 
 namespace giada::v
 {
-class geMainMenu : public gePack
+class geMainMenu : public geFlex
 {
 public:
-       geMainMenu(int x, int y);
+       geMainMenu();
 
 private:
        void cb_file();
index 737b47541379500eaa01d1ea8db636b3313022c1..7c93a05b8938def13c1226d126b121f02e670626 100644 (file)
 #include "glue/main.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
-geMainTimer::geMainTimer(int x, int y)
-: gePack(x, y, Direction::HORIZONTAL)
+geMainTimer::geMainTimer()
+: geFlex(Direction::HORIZONTAL, G_GUI_INNER_MARGIN)
 {
-       m_bpm        = new geButton(0, 0, 60, G_GUI_UNIT);
-       m_meter      = new geButton(0, 0, 60, G_GUI_UNIT);
-       m_quantizer  = new geChoice(0, 0, 60, G_GUI_UNIT);
-       m_multiplier = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", multiplyOff_xpm, multiplyOn_xpm);
-       m_divider    = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", divideOff_xpm, divideOn_xpm);
-       add(m_quantizer);
-       add(m_bpm);
-       add(m_meter);
-       add(m_multiplier);
-       add(m_divider);
-
-       resizable(nullptr); // don't resize any widget
-
-       m_bpm->copy_tooltip("Beats per minute (BPM)");
-       m_meter->copy_tooltip("Beats and bars");
-       m_quantizer->copy_tooltip("Live quantizer");
-       m_multiplier->copy_tooltip("Beat multiplier");
-       m_divider->copy_tooltip("Beat divider");
+       m_bpm        = new geButton();
+       m_meter      = new geButton();
+       m_quantizer  = new geChoice();
+       m_multiplier = new geButton("", multiplyOff_xpm, multiplyOn_xpm);
+       m_divider    = new geButton("", divideOff_xpm, divideOn_xpm);
+       add(m_quantizer, 60);
+       add(m_bpm, 60);
+       add(m_meter, 60);
+       add(m_multiplier, G_GUI_UNIT);
+       add(m_divider, G_GUI_UNIT);
+       end();
+
+       m_bpm->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TIMER_LABEL_BPM));
+       m_meter->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TIMER_LABEL_METER));
+       m_quantizer->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TIMER_LABEL_QUANTIZER));
+       m_multiplier->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TIMER_LABEL_MULTIPLIER));
+       m_divider->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TIMER_LABEL_DIVIDER));
 
        m_bpm->onClick        = [&bpm = m_bpm]() { c::layout::openBpmWindow(bpm->label()); };
        m_meter->onClick      = [&timer = m_timer]() { c::layout::openBeatsWindow(timer.beats, timer.bars); };
        m_multiplier->onClick = []() { c::events::multiplyBeats(); };
        m_divider->onClick    = []() { c::events::divideBeats(); };
 
-       m_quantizer->addItem("off");
+       m_quantizer->addItem(g_ui.langMapper.get(LangMap::COMMON_OFF));
        m_quantizer->addItem("1\\/1");
        m_quantizer->addItem("1\\/2");
        m_quantizer->addItem("1\\/3");
index c1ee8d5750f11a1fec4cfa71aa6b1e00ecca7a90..ef53b70d3155468c72aa93949cd2367df6a00578 100644 (file)
 #define GE_MAIN_TIMER_H
 
 #include "glue/main.h"
-#include "gui/elems/basics/pack.h"
+#include "gui/elems/basics/flex.h"
 
 namespace giada::v
 {
 class geButton;
 class geChoice;
-class geMainTimer : public gePack
+class geMainTimer : public geFlex
 {
 public:
-       geMainTimer(int x, int y);
+       geMainTimer();
 
        void refresh();
        void rebuild();
index c0d680a9ce251ae761bdf19d5935a831e65201e8..c60553e13858e10e44a3e89f90c144e60b9e2fdc 100644 (file)
 #include "core/graphics.h"
 #include "glue/events.h"
 #include "glue/main.h"
+#include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
+#include "gui/elems/basics/flex.h"
+#include "gui/elems/basics/statusButton.h"
+#include "gui/ui.h"
+
+extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
-geMainTransport::geMainTransport(int x, int y)
-: gePack(x, y, Direction::HORIZONTAL)
-, m_rewind(0, 0, 25, 25, "", rewindOff_xpm, rewindOn_xpm)
-, m_play(0, 0, 25, 25, play_xpm, pause_xpm)
-, m_spacer1(0, 0, 10, 25)
-, m_recTriggerMode(0, 0, 15, 25, recTriggerModeOff_xpm, recTriggerModeOn_xpm)
-, m_recAction(0, 0, 25, 25, recOff_xpm, recOn_xpm)
-, m_recInput(0, 0, 25, 25, inputRecOff_xpm, inputRecOn_xpm)
-, m_inputRecMode(0, 0, 15, 25, freeInputRecOff_xpm, freeInputRecOn_xpm)
-, m_spacer2(0, 0, 10, 25)
-, m_metronome(0, 0, 15, 25, metronomeOff_xpm, metronomeOn_xpm)
+geMainTransport::geMainTransport()
+: geFlex(Direction::HORIZONTAL, G_GUI_INNER_MARGIN)
 {
-       add(&m_rewind);
-       add(&m_play);
-       add(&m_spacer1);
-       add(&m_recTriggerMode);
-       add(&m_recAction);
-       add(&m_recInput);
-       add(&m_inputRecMode);
-       add(&m_spacer2);
-       add(&m_metronome);
+       m_rewind         = new geButton("", rewindOff_xpm, rewindOn_xpm);
+       m_play           = new geStatusButton(play_xpm, pause_xpm);
+       m_recTriggerMode = new geStatusButton(recTriggerModeOff_xpm, recTriggerModeOn_xpm);
+       m_recAction      = new geStatusButton(recOff_xpm, recOn_xpm);
+       m_recInput       = new geStatusButton(inputRecOff_xpm, inputRecOn_xpm);
+       m_inputRecMode   = new geStatusButton(freeInputRecOff_xpm, freeInputRecOn_xpm);
+       m_metronome      = new geStatusButton(metronomeOff_xpm, metronomeOn_xpm);
+       add(m_rewind, 25);
+       add(m_play, 25);
+       add(new geBox(), 10);
+       add(m_recTriggerMode, 15);
+       add(m_recAction, 25);
+       add(m_recInput, 25);
+       add(m_inputRecMode, 15);
+       add(new geBox(), 10);
+       add(m_metronome, 15);
+       end();
 
-       m_rewind.copy_tooltip("Rewind");
-       m_play.copy_tooltip("Play/Stop");
-       m_recTriggerMode.copy_tooltip("Record-on-signal mode\n\nIf enabled, action "
-                                     "and audio recording will start only when a signal (key press or audio) "
-                                     "is detected.");
-       m_recAction.copy_tooltip("Record actions");
-       m_recInput.copy_tooltip("Record audio");
-       m_inputRecMode.copy_tooltip("Free loop-length mode\n\nIf enabled, the sequencer "
-                                   "will adjust to the length of your first audio recording. "
-                                   "Available only if there are no other audio samples in the "
-                                   "project.");
-       m_metronome.copy_tooltip("Metronome");
+       m_rewind->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TRANSPORT_LABEL_REWIND));
+       m_play->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TRANSPORT_LABEL_PLAY));
+       m_recTriggerMode->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TRANSPORT_LABEL_RECTRIGGERMODE));
+       m_recAction->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TRANSPORT_LABEL_RECACTIONS));
+       m_recInput->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TRANSPORT_LABEL_RECINPUT));
+       m_inputRecMode->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TRANSPORT_LABEL_RECINPUTMODE));
+       m_metronome->copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_TRANSPORT_LABEL_METRONOME));
 
-       m_rewind.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_rewind->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::rewindSequencer(Thread::MAIN);
        });
 
-       m_play.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_play->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleSequencer(Thread::MAIN);
        });
 
-       m_recAction.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_recAction->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleActionRecording();
        });
 
-       m_recInput.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_recInput->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleInputRecording();
        });
 
-       m_recTriggerMode.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_recTriggerMode->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::main::toggleRecOnSignal();
        });
 
-       m_inputRecMode.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_inputRecMode->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::main::toggleFreeInputRec();
        });
 
-       m_metronome.type(FL_TOGGLE_BUTTON);
-       m_metronome.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_metronome->type(FL_TOGGLE_BUTTON);
+       m_metronome->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleMetronome();
        });
 }
@@ -104,11 +105,11 @@ void geMainTransport::refresh()
 {
        c::main::Transport transport = c::main::getTransport();
 
-       m_play.setStatus(transport.isRunning);
-       m_recAction.setStatus(transport.isRecordingAction);
-       m_recInput.setStatus(transport.isRecordingInput);
-       m_metronome.setStatus(transport.isMetronomeOn);
-       m_recTriggerMode.setStatus(transport.recTriggerMode == RecTriggerMode::SIGNAL);
-       m_inputRecMode.setStatus(transport.inputRecMode == InputRecMode::FREE);
+       m_play->setStatus(transport.isRunning);
+       m_recAction->setStatus(transport.isRecordingAction);
+       m_recInput->setStatus(transport.isRecordingInput);
+       m_metronome->setStatus(transport.isMetronomeOn);
+       m_recTriggerMode->setStatus(transport.recTriggerMode == RecTriggerMode::SIGNAL);
+       m_inputRecMode->setStatus(transport.inputRecMode == InputRecMode::FREE);
 }
 } // namespace giada::v
index f9e97a46e2b104022d0b848b04d54d88a91eed89..d752a24d77679fb44a9dbde1281674c2bba7fb26 100644 (file)
 #ifndef GE_MAIN_TRANSPORT_H
 #define GE_MAIN_TRANSPORT_H
 
-#include "gui/elems/basics/box.h"
-#include "gui/elems/basics/button.h"
-#include "gui/elems/basics/pack.h"
-#include "gui/elems/basics/statusButton.h"
+#include "gui/elems/basics/flex.h"
 
 namespace giada::v
 {
-class geMainTransport : public gePack
+class geButton;
+class geStatusButton;
+class geMainTransport : public geFlex
 {
 public:
-       geMainTransport(int x, int y);
+       geMainTransport();
 
        void refresh();
 
 private:
-       geButton       m_rewind;
-       geStatusButton m_play;
-       geBox          m_spacer1;
-       geStatusButton m_recTriggerMode;
-       geStatusButton m_recAction;
-       geStatusButton m_recInput;
-       geStatusButton m_inputRecMode;
-       geBox          m_spacer2;
-       geStatusButton m_metronome;
+       geButton*       m_rewind;
+       geStatusButton* m_play;
+       geStatusButton* m_recTriggerMode;
+       geStatusButton* m_recAction;
+       geStatusButton* m_recInput;
+       geStatusButton* m_inputRecMode;
+       geStatusButton* m_metronome;
 };
 } // namespace giada::v
 
index f0e38a5ddc0c343d3c3325afcd43c0de21272d07..b9bea8d54e6d12edd8f5c6a86a91488a9c080089 100644 (file)
 #include "sequencer.h"
 #include "core/const.h"
 #include "gui/drawing.h"
+#include "gui/ui.h"
 #include "utils/math.h"
 #include <FL/fl_draw.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
-geSequencer::geSequencer(int x, int y, int w, int h)
-: Fl_Box(x, y, w, h)
+geSequencer::geSequencer()
+: geBox()
 {
-       copy_tooltip("Main sequencer");
+       copy_tooltip(g_ui.langMapper.get(LangMap::MAIN_SEQUENCER_LABEL));
 }
 
 /* -------------------------------------------------------------------------- */
index 1d6dab2d8a67ad4af90b1d6813277da7dc84cd63..0242a049c8dc9fff89442ae35034c252689b9f2b 100644 (file)
 #include "core/types.h"
 #include "deps/geompp/src/rect.hpp"
 #include "glue/main.h"
-#include <FL/Fl_Box.H>
+#include "gui/elems/basics/box.h"
 
 namespace giada::v
 {
-class geSequencer : public Fl_Box
+class geSequencer : public geBox
 {
 public:
-       geSequencer(int x, int y, int w, int h);
+       geSequencer();
 
        void draw() override;
 
index e730c23d77102231970f1a75561ae1dea170a0ab..59c2b829855b791adc240254b7b3478bed288e46 100644 (file)
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
+#include "gui/ui.h"
 #include "utils/string.h"
 #include <cassert>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 geMidiLearner::geMidiLearner(int x, int y, int w, int h, std::string l, int param)
@@ -43,7 +46,7 @@ geMidiLearner::geMidiLearner(int x, int y, int w, int h, std::string l, int para
 {
        m_text     = new geBox(l.c_str());
        m_valueBtn = new geButton();
-       m_button   = new geButton("learn");
+       m_button   = new geButton(g_ui.langMapper.get(LangMap::COMMON_LEARN));
 
        add(m_text);
        add(m_valueBtn, 80);
@@ -77,7 +80,7 @@ geMidiLearner::geMidiLearner(int x, int y, int w, int h, std::string l, int para
 
 void geMidiLearner::update(uint32_t value)
 {
-       std::string tmp = "(not set)";
+       std::string tmp = g_ui.langMapper.get(LangMap::COMMON_NOTSET);
 
        if (value != 0x0)
        {
index c79b1ef2fb344b7ad71856bb78f15b041c4633f2..989186e78557e252b74b9b56013f965f58d7cc18 100644 (file)
@@ -30,9 +30,7 @@
 #include "gui/elems/basics/box.h"
 #include <cassert>
 
-namespace giada
-{
-namespace v
+namespace giada::v
 {
 constexpr int LEARNER_WIDTH = 284;
 
@@ -86,5 +84,4 @@ void geMidiLearnerPack::setEnabled(bool v)
                for (auto* l : learners)
                        l->deactivate();
 }
-} // namespace v
-} // namespace giada
+} // namespace giada::v
\ No newline at end of file
index 1622150304d4c74c2cfdfba50958eef9f1b1ad7a..76129b85820c2a30bc100c6f9e9989ef549b1d12 100644 (file)
@@ -32,9 +32,7 @@
 #include <string>
 #include <vector>
 
-namespace giada
-{
-namespace v
+namespace giada::v
 {
 class geMidiLearnerPack : public gePack
 {
@@ -47,11 +45,10 @@ public:
 
        std::vector<geMidiLearner*> learners;
 
-  private:
+private:
        std::function<void(uint32_t)> m_onStartLearn;
        std::function<void(uint32_t)> m_onClearLearn;
 };
-} // namespace v
-} // namespace giada
+} // namespace giada::v
 
 #endif
index 2a4d3dd4bda937aeb915e4cbd12bd47b89b1180c..1f0d8b32e5e075c4f31ff1e0cb3365cf55625265 100644 (file)
 #include "core/plugins/pluginManager.h"
 #include "glue/plugin.h"
 #include "gui/elems/basics/boxtypes.h"
-#include <FL/fl_draw.H>
+#include "gui/ui.h"
+#include "utils/gui.h"
+#include <fmt/core.h>
+
+extern giada::v::Ui g_ui;
 
 namespace giada::v
 {
@@ -73,7 +77,7 @@ void gePluginBrowser::refresh()
 {
        clear();
 
-       add("NAME\tMANUFACTURER\tCATEGORY\tFORMAT\tUID");
+       add(g_ui.langMapper.get(LangMap::PLUGINCHOOSER_HEADER));
        add("---\t---\t---\t---\t---");
 
        for (m::PluginManager::PluginInfo pi : c::plugin::getPluginsInfo())
@@ -83,11 +87,11 @@ void gePluginBrowser::refresh()
                {
                        std::string m = pi.exists ? "" : "@-";
 
-                       s = m + pi.name + "\t" + m + pi.manufacturerName + "\t" + m +
-                           pi.category + "\t" + m + pi.format + "\t" + m + pi.uid;
+                       s = fmt::format("{0}{1}\t{0}{2}\t{0}{3}\t{0}{4}\t{0}{5}",
+                           m, pi.name, pi.manufacturerName, pi.category, pi.format, pi.uid);
                }
                else
-                       std::string s = "?\t?\t?\t?\t? " + pi.uid + " ?";
+                       s = fmt::format("?\t?\t?\t?\t? {} ?", pi.uid);
 
                add(s.c_str());
        }
@@ -97,23 +101,20 @@ void gePluginBrowser::refresh()
 
 void gePluginBrowser::computeWidths()
 {
-       int w0, w1, w3;
+       constexpr int PADDDING = 60;
+
        for (m::PluginManager::PluginInfo pi : c::plugin::getPluginsInfo())
        {
-               w0 = static_cast<int>(fl_width(pi.name.c_str()));
-               w1 = static_cast<int>(fl_width(pi.manufacturerName.c_str()));
-               w3 = static_cast<int>(fl_width(pi.format.c_str()));
-               if (w0 > m_widths[0])
-                       m_widths[0] = w0;
-               if (w1 > m_widths[1])
-                       m_widths[1] = w1;
-               if (w3 > m_widths[3])
-                       m_widths[3] = w3;
+               // Explicit type std::max<int> to fix MINMAX macro hell on Windows
+               m_widths[0] = std::max<int>(u::gui::getStringRect(pi.name).w, m_widths[0]);
+               m_widths[1] = std::max<int>(u::gui::getStringRect(pi.manufacturerName).w, m_widths[1]);
+               m_widths[2] = std::max<int>(u::gui::getStringRect(pi.category).w, m_widths[2]);
+               m_widths[3] = std::max<int>(u::gui::getStringRect(pi.format).w, m_widths[3]);
        }
-       m_widths[0] += 60;
-       m_widths[1] += 60;
-       m_widths[2] = static_cast<int>(fl_width("CATEGORY") + 60);
-       m_widths[3] += 60;
+       m_widths[0] += PADDDING;
+       m_widths[1] += PADDDING;
+       m_widths[2] += PADDDING;
+       m_widths[3] += PADDDING;
        m_widths[4] = 0;
 }
 } // namespace giada::v
index 34eecda1784e2eacbd40a8abce50251f1dca0167..43ce016b7f0f45aafb380b6d7e6c04b89cb47d3e 100644 (file)
 #include "gui/dialogs/pluginWindowGUI.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/log.h"
 #include <cassert>
 #include <string>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gePluginElement::gePluginElement(int x, int y, c::plugin::Plugin data)
@@ -87,7 +90,8 @@ gePluginElement::gePluginElement(int x, int y, c::plugin::Plugin data)
 
        if (program.countItems() == 0)
        {
-               program.addItem("-- no programs --\0");
+               program.addItem(g_ui.langMapper.get(LangMap::PLUGINLIST_NOPROGRAMS));
+               program.showItem(0);
                program.deactivate();
        }
        else
diff --git a/src/gui/elems/sampleEditor/boostTool.cpp b/src/gui/elems/sampleEditor/boostTool.cpp
deleted file mode 100644 (file)
index 5c8dea0..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-#include "boostTool.h"
-#include "core/const.h"
-#include "core/waveFx.h"
-#include "glue/channel.h"
-#include "gui/dialogs/sampleEditor.h"
-#include "gui/elems/basics/box.h"
-#include "gui/elems/basics/button.h"
-#include "gui/elems/basics/dial.h"
-#include "gui/elems/basics/input.h"
-#include "utils/gui.h"
-#include "utils/math.h"
-#include "utils/string.h"
-#include "waveTools.h"
-#include <FL/Fl.H>
-
-namespace giada::v
-{
-geBoostTool::geBoostTool(int X, int Y)
-: Fl_Pack(X, Y, 220, G_GUI_UNIT)
-{
-       type(Fl_Pack::HORIZONTAL);
-       spacing(G_GUI_INNER_MARGIN);
-
-       begin();
-       label     = new geBox(0, 0, u::gui::getStringRect("Boost").w, G_GUI_UNIT, "Boost", FL_ALIGN_RIGHT);
-       dial      = new geDial(0, 0, G_GUI_UNIT, G_GUI_UNIT);
-       input     = new geInput(0, 0, 70, G_GUI_UNIT);
-       normalize = new geButton(0, 0, 70, G_GUI_UNIT, "Normalize");
-       end();
-
-       dial->range(1.0f, 10.0f);
-       dial->callback(cb_setBoost, (void*)this);
-       dial->when(FL_WHEN_CHANGED | FL_WHEN_RELEASE);
-
-       input->callback(cb_setBoostNum, (void*)this);
-
-       normalize->callback(cb_normalize, (void*)this);
-}
-
-/* -------------------------------------------------------------------------- */
-
-void geBoostTool::rebuild()
-{
-       /*
-       const m::SampleChannel* ch = static_cast<gdSampleEditor*>(window())->ch;
-
-       input->value(u::string::fToString(u::math::linearToDB(ch->getBoost()), 2).c_str());  // 2 digits
-       // A dial greater than it's max value goes crazy
-       dial->value(ch->getBoost() <= 10.0f ? ch->getBoost() : 10.0f);*/
-}
-
-/* -------------------------------------------------------------------------- */
-
-void geBoostTool::cb_setBoost(Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_setBoost(); }
-void geBoostTool::cb_setBoostNum(Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_setBoostNum(); }
-void geBoostTool::cb_normalize(Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_normalize(); }
-
-/* -------------------------------------------------------------------------- */
-
-void geBoostTool::cb_setBoost()
-{
-       /*const m::SampleChannel* ch = static_cast<gdSampleEditor*>(window())->ch;
-
-       c::channel::setBoost(ch->id, dial->value());*/
-}
-
-/* -------------------------------------------------------------------------- */
-
-void geBoostTool::cb_setBoostNum()
-{
-       /*const m::SampleChannel* ch = static_cast<gdSampleEditor*>(window())->ch;
-
-       c::channel::setBoost(ch->id, u::math::dBtoLinear(atof(input->value())));*/
-}
-
-/* -------------------------------------------------------------------------- */
-
-void geBoostTool::cb_normalize()
-{
-}
-} // namespace giada::v
diff --git a/src/gui/elems/sampleEditor/boostTool.h b/src/gui/elems/sampleEditor/boostTool.h
deleted file mode 100644 (file)
index a01f9c3..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-#ifndef GE_BOOST_TOOL_H
-#define GE_BOOST_TOOL_H
-
-#include <FL/Fl_Pack.H>
-
-class geInput;
-
-namespace giada::v
-{
-class geBox;
-class geDial;
-class geButton;
-class geBoostTool : public Fl_Pack
-{
-public:
-       geBoostTool(int x, int y);
-
-       void rebuild();
-
-private:
-       static void cb_setBoost(Fl_Widget* /*w*/, void* p);
-       static void cb_setBoostNum(Fl_Widget* /*w*/, void* p);
-       static void cb_normalize(Fl_Widget* /*w*/, void* p);
-       void        cb_setBoost();
-       void        cb_setBoostNum();
-       void        cb_normalize();
-
-       geBox*    label;
-       geDial*   dial;
-       geInput*  input;
-       geButton* normalize;
-};
-} // namespace giada::v
-
-#endif
index bcf685bfb50fcb8edcd0ce71537efa47d7667d88..cee5e7d62fda682bc14a0420a1febb0c14b5f76c 100644 (file)
 #include "core/waveFx.h"
 #include "glue/events.h"
 #include "gui/dialogs/sampleEditor.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/math.h"
 #include "utils/string.h"
 #include "waveTools.h"
 #include <FL/Fl.H>
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 gePanTool::gePanTool(const c::sampleEditor::Data& d, int x, int y)
 : gePack(x, y, Direction::HORIZONTAL)
 , m_data(nullptr)
-, m_label(0, 0, 60, G_GUI_UNIT, "Pan", FL_ALIGN_LEFT)
+, m_label(0, 0, 60, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_PAN), FL_ALIGN_LEFT)
 , m_dial(0, 0, G_GUI_UNIT, G_GUI_UNIT)
 , m_input(0, 0, 70, G_GUI_UNIT)
-, m_reset(0, 0, 70, G_GUI_UNIT, "Reset")
+, m_reset(0, 0, 70, G_GUI_UNIT, g_ui.langMapper.get(LangMap::COMMON_RESET))
 {
        add(&m_label);
        add(&m_dial);
@@ -111,5 +112,4 @@ void gePanTool::cb_panReset()
 {
        c::events::sendChannelPan(m_data->channelId, 0.5f);
 }
-} // namespace v
-} // namespace giada
+} // namespace giada::v
\ No newline at end of file
index 69cad2b8eb89edfb593484328f1e91051089fb18..4df26341b507cb27870ea1c40192e589e80db471 100644 (file)
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/dial.h"
 #include "gui/elems/basics/input.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <FL/Fl.H>
 
+extern giada::v::Ui g_ui;
+
 namespace giada::v
 {
 gePitchTool::gePitchTool(const c::sampleEditor::Data& d, int x, int y)
 : gePack(x, y, Direction::HORIZONTAL)
 , m_data(nullptr)
-, m_label(0, 0, 60, G_GUI_UNIT, "Pitch", FL_ALIGN_LEFT)
+, m_label(0, 0, 60, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_PITCH), FL_ALIGN_LEFT)
 , m_dial(0, 0, G_GUI_UNIT, G_GUI_UNIT)
 , m_input(0, 0, 70, G_GUI_UNIT)
-, m_pitchToBar(0, 0, 70, G_GUI_UNIT, "To bar")
-, m_pitchToSong(0, 0, 70, G_GUI_UNIT, "To song")
+, m_pitchToBar(0, 0, 70, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_PITCH_TOBAR))
+, m_pitchToSong(0, 0, 70, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_PITCH_TOSONG))
 , m_pitchHalf(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", divideOff_xpm, divideOn_xpm)
 , m_pitchDouble(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", multiplyOff_xpm, multiplyOn_xpm)
-, m_pitchReset(0, 0, 70, G_GUI_UNIT, "Reset")
+, m_pitchReset(0, 0, 70, G_GUI_UNIT, g_ui.langMapper.get(LangMap::COMMON_RESET))
 {
        add(&m_label);
        add(&m_dial);
index 8f8e85dfc4d492641aea059c1a09928b3081ca4f..b27a1ac028b2058bae48f5ab33023bf96abc2d96 100644 (file)
 #include "glue/channel.h"
 #include "glue/sampleEditor.h"
 #include "gui/dialogs/sampleEditor.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include "waveTools.h"
 #include <FL/Fl.H>
 #include <cassert>
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 geRangeTool::geRangeTool(const c::sampleEditor::Data& d, int x, int y)
 : gePack(x, y, Direction::HORIZONTAL)
 , m_data(nullptr)
-, m_label(0, 0, 60, G_GUI_UNIT, "Range", FL_ALIGN_LEFT)
+, m_label(0, 0, 60, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_RANGE), FL_ALIGN_LEFT)
 , m_begin(0, 0, 70, G_GUI_UNIT)
 , m_end(0, 0, 70, G_GUI_UNIT)
-, m_reset(0, 0, 70, G_GUI_UNIT, "Reset")
+, m_reset(0, 0, 70, G_GUI_UNIT, g_ui.langMapper.get(LangMap::COMMON_RESET))
 {
        add(&m_label);
        add(&m_begin);
@@ -100,6 +101,4 @@ void geRangeTool::cb_resetStartEnd()
 {
        c::sampleEditor::setBeginEnd(m_data->channelId, 0, m_data->waveSize - 1);
 }
-
-} // namespace v
-} // namespace giada
+} // namespace giada::v
\ No newline at end of file
index f5c56c33e9ae97f85136daf45de644975c0649b3..faec3f99114c8f711c2cda0a15e561d6fee59465 100644 (file)
 #include "glue/sampleEditor.h"
 #include "gui/dialogs/sampleEditor.h"
 #include "gui/dialogs/warnings.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/string.h"
 #include <cassert>
 #include <cstdlib>
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 geShiftTool::geShiftTool(const c::sampleEditor::Data& d, int x, int y)
 : gePack(x, y, Direction::HORIZONTAL)
 , m_data(nullptr)
-, m_label(0, 0, 60, G_GUI_UNIT, "Shift", FL_ALIGN_LEFT)
+, m_label(0, 0, 60, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_SHIFT), FL_ALIGN_LEFT)
 , m_shift(0, 0, 70, G_GUI_UNIT)
-, m_reset(0, 0, 70, G_GUI_UNIT, "Reset")
+, m_reset(0, 0, 70, G_GUI_UNIT, g_ui.langMapper.get(LangMap::COMMON_RESET))
 {
        add(&m_label);
        add(&m_shift);
@@ -99,5 +100,4 @@ void geShiftTool::shift(int f)
 {
        c::sampleEditor::shift(m_data->channelId, f);
 }
-} // namespace v
-} // namespace giada
+} // namespace giada::v
\ No newline at end of file
index 5fd7d254787863815820875eff9d6c6b878f9d22..08fd4330fbc70feb0bb3b7f98817fa6d3f0d0403 100644 (file)
@@ -29,6 +29,7 @@
 #include "glue/events.h"
 #include "gui/dialogs/sampleEditor.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "utils/math.h"
 #include "utils/string.h"
 #include <cmath>
 #include <cstdlib>
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 geVolumeTool::geVolumeTool(const c::sampleEditor::Data& d, int x, int y)
 : gePack(x, y, Direction::HORIZONTAL)
 , m_data(nullptr)
-, m_label(0, 0, 60, G_GUI_UNIT, "Volume", FL_ALIGN_LEFT)
+, m_label(0, 0, 60, G_GUI_UNIT, g_ui.langMapper.get(LangMap::SAMPLEEDITOR_VOLUME), FL_ALIGN_LEFT)
 , m_dial(0, 0, G_GUI_UNIT, G_GUI_UNIT)
 , m_input(0, 0, 70, G_GUI_UNIT)
 {
@@ -99,5 +100,4 @@ void geVolumeTool::cb_setVolumeNum()
        c::events::setChannelVolume(m_data->channelId, u::math::dBtoLinear(atof(m_input.value())),
            Thread::MAIN);
 }
-} // namespace v
-} // namespace giada
+} // namespace giada::v
\ No newline at end of file
index e271d3c0c3a3a335fa4ca51a7c954290dede74ab..0a1d51bf27f4601a1165b86ada1207c4bd84305b 100644 (file)
 #include "glue/sampleEditor.h"
 #include "gui/dialogs/sampleEditor.h"
 #include "gui/elems/basics/boxtypes.h"
+#include "gui/ui.h"
 #include "utils/gui.h"
 #include "waveform.h"
 #include <FL/Fl_Menu_Button.H>
 #include <FL/Fl_Menu_Item.H>
 #include <cstdint>
 
-namespace giada
-{
-namespace v
+extern giada::v::Ui g_ui;
+
+namespace giada::v
 {
 namespace
 {
@@ -198,18 +199,18 @@ int geWaveTools::handle(int e)
 void geWaveTools::openMenu()
 {
        Fl_Menu_Item menu[] = {
-           u::gui::makeMenuItem("Cut", menuCallback_, (void*)Menu::CUT),
-           u::gui::makeMenuItem("Copy", menuCallback_, (void*)Menu::COPY),
-           u::gui::makeMenuItem("Paste", menuCallback_, (void*)Menu::PASTE),
-           u::gui::makeMenuItem("Trim", menuCallback_, (void*)Menu::TRIM),
-           u::gui::makeMenuItem("Silence", menuCallback_, (void*)Menu::SILENCE),
-           u::gui::makeMenuItem("Reverse", menuCallback_, (void*)Menu::REVERSE),
-           u::gui::makeMenuItem("Normalize", menuCallback_, (void*)Menu::NORMALIZE),
-           u::gui::makeMenuItem("Fade in", menuCallback_, (void*)Menu::FADE_IN),
-           u::gui::makeMenuItem("Fade out", menuCallback_, (void*)Menu::FADE_OUT),
-           u::gui::makeMenuItem("Smooth edges", menuCallback_, (void*)Menu::SMOOTH_EDGES),
-           u::gui::makeMenuItem("Set begin/end here", menuCallback_, (void*)Menu::SET_BEGIN_END),
-           u::gui::makeMenuItem("Copy to new channel", menuCallback_, (void*)Menu::TO_NEW_CHANNEL),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_CUT), menuCallback_, (void*)Menu::CUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_COPY), menuCallback_, (void*)Menu::COPY),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_PASTE), menuCallback_, (void*)Menu::PASTE),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_TRIM), menuCallback_, (void*)Menu::TRIM),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_SILENCE), menuCallback_, (void*)Menu::SILENCE),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_REVERSE), menuCallback_, (void*)Menu::REVERSE),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_NORMALIZE), menuCallback_, (void*)Menu::NORMALIZE),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_FADE_IN), menuCallback_, (void*)Menu::FADE_IN),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_FADE_OUT), menuCallback_, (void*)Menu::FADE_OUT),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_SMOOTH_EDGES), menuCallback_, (void*)Menu::SMOOTH_EDGES),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_SET_BEGIN_END), menuCallback_, (void*)Menu::SET_BEGIN_END),
+           u::gui::makeMenuItem(g_ui.langMapper.get(LangMap::SAMPLEEDITOR_TOOLS_TO_NEW_CHANNEL), menuCallback_, (void*)Menu::TO_NEW_CHANNEL),
            {}};
 
        if (!waveform->isSelected())
@@ -239,6 +240,4 @@ void geWaveTools::openMenu()
 
        return;
 }
-
-} // namespace v
-} // namespace giada
+} // namespace giada::v
\ No newline at end of file
diff --git a/src/gui/langMapper.cpp b/src/gui/langMapper.cpp
new file mode 100644 (file)
index 0000000..d7ceeca
--- /dev/null
@@ -0,0 +1,388 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "gui/langMapper.h"
+#include "utils/fs.h"
+#include "utils/log.h"
+#include <filesystem>
+#include <fstream>
+
+namespace nl = nlohmann;
+
+namespace giada::v
+{
+LangMap::LangMap()
+: m_default("[Not set]")
+{
+       m_data[COMMON_OK]         = "Ok";
+       m_data[COMMON_CANCEL]     = "Cancel";
+       m_data[COMMON_YES]        = "Yes";
+       m_data[COMMON_NO]         = "No";
+       m_data[COMMON_OFF]        = "Off";
+       m_data[COMMON_SELECT]     = "Select";
+       m_data[COMMON_LOAD]       = "Load";
+       m_data[COMMON_SAVE]       = "Save";
+       m_data[COMMON_WARNING]    = "Warning";
+       m_data[COMMON_CLOSE]      = "Close";
+       m_data[COMMON_ADD]        = "Add";
+       m_data[COMMON_CLEAR]      = "Clear";
+       m_data[COMMON_RELOAD]     = "Reload";
+       m_data[COMMON_RESET]      = "Reset";
+       m_data[COMMON_ZOOMIN]     = "Zoom in";
+       m_data[COMMON_ZOOMOUT]    = "Zoom out";
+       m_data[COMMON_GRIDRES]    = "Grid resolution";
+       m_data[COMMON_SNAPTOGRID] = "Snap to grid";
+       m_data[COMMON_BIND]       = "Bind";
+       m_data[COMMON_LEARN]      = "Learn";
+       m_data[COMMON_NOTSET]     = "(not set)";
+       m_data[COMMON_NONE]       = "None";
+
+       m_data[MESSAGE_MAIN_FREEALLSAMPLES]           = "Free all Sample channels: are you sure?";
+       m_data[MESSAGE_MAIN_CLEARALLACTIONS]          = "Clear all actions: are you sure?";
+       m_data[MESSAGE_MAIN_CLEARALLVOLUMEACTIONS]    = "Clear all volume actions: are you sure?";
+       m_data[MESSAGE_MAIN_CLEARALLSTARTSTOPACTIONS] = "Clear all start/stop actions: are you sure?";
+       m_data[MESSAGE_MAIN_CLOSEPROJECT]             = "Close project: are you sure?";
+
+       m_data[MESSAGE_INIT_WRONGSYSTEM] = "Your soundcard isn't configured correctly.\n"
+                                          "Check the configuration and restart Giada.";
+       m_data[MESSAGE_INIT_QUITGIADA] = "Quit Giada: are you sure?";
+
+       m_data[MESSAGE_CHANNEL_MULTICHANNOTSUPPORTED] = "Multichannel samples not supported.";
+       m_data[MESSAGE_CHANNEL_CANTREADSAMPLE]        = "Unable to read this sample.";
+       m_data[MESSAGE_CHANNEL_PATHTOOLONG]           = "File path too long.";
+       m_data[MESSAGE_CHANNEL_NOFILESPECIFIED]       = "No file specified.";
+       m_data[MESSAGE_CHANNEL_LOADINGSAMPLES]        = "Loading samples...";
+       m_data[MESSAGE_CHANNEL_LOADINGSAMPLESERROR]   = "Some files weren't loaded successfully.";
+       m_data[MESSAGE_CHANNEL_DELETE]                = "Delete channel: are you sure?";
+       m_data[MESSAGE_CHANNEL_FREE]                  = "Free channel: are you sure?";
+
+       m_data[MESSAGE_STORAGE_PATCHUNREADABLE]    = "This patch is unreadable.";
+       m_data[MESSAGE_STORAGE_PATCHINVALID]       = "This patch is not valid.";
+       m_data[MESSAGE_STORAGE_PATCHUNSUPPORTED]   = "This patch format is no longer supported.";
+       m_data[MESSAGE_STORAGE_PROJECTEXISTS]      = "Project exists: overwrite?";
+       m_data[MESSAGE_STORAGE_LOADINGPROJECT]     = "Loading project...";
+       m_data[MESSAGE_STORAGE_LOADINGSAMPLE]      = "Loading sample...";
+       m_data[MESSAGE_STORAGE_SAVINGPROJECT]      = "Saving project...";
+       m_data[MESSAGE_STORAGE_SAVINGPROJECTERROR] = "Unable to save the project!";
+       m_data[MESSAGE_STORAGE_CHOOSEPROJECTNAME]  = "Please choose a project name.";
+       m_data[MESSAGE_STORAGE_CHOOSEFILENAME]     = "Please choose a file name.";
+       m_data[MESSAGE_STORAGE_FILEEXISTS]         = "File exists: overwrite?";
+       m_data[MESSAGE_STORAGE_SAVINGFILEERROR]    = "Unable to save this sample!";
+
+       m_data[MAIN_MENU_FILE]                 = "File";
+       m_data[MAIN_MENU_FILE_OPENPROJECT]     = "Open project...";
+       m_data[MAIN_MENU_FILE_SAVEPROJECT]     = "Save project...";
+       m_data[MAIN_MENU_FILE_CLOSEPROJECT]    = "Close project";
+       m_data[MAIN_MENU_FILE_QUIT]            = "Quit Giada";
+       m_data[MAIN_MENU_EDIT]                 = "Edit";
+       m_data[MAIN_MENU_EDIT_FREEALLSAMPLES]  = "Free all Sample channels";
+       m_data[MAIN_MENU_EDIT_CLEARALLACTIONS] = "Clear all actions";
+       m_data[MAIN_MENU_EDIT_SETUPMIDIINPUT]  = "Setup global MIDI input...";
+       m_data[MAIN_MENU_CONFIG]               = "Config";
+       m_data[MAIN_MENU_ABOUT]                = "About";
+
+       m_data[MAIN_IO_LABEL_OUTMETER] = "Main output meter";
+       m_data[MAIN_IO_LABEL_INMETER]  = "Main input meter";
+       m_data[MAIN_IO_LABEL_OUTVOL]   = "Main output volume";
+       m_data[MAIN_IO_LABEL_INVOL]    = "Main input volume";
+       m_data[MAIN_IO_LABEL_INTOOUT]  = "Stream linker\n\nConnects input to output to enable \"hear what you're playing\" mode.";
+       m_data[MAIN_IO_LABEL_FXOUT]    = "Main output plug-ins";
+       m_data[MAIN_IO_LABEL_FXIN]     = "Main input plug-ins";
+
+       m_data[MAIN_TIMER_LABEL_BPM]        = "Beats per minute (BPM)";
+       m_data[MAIN_TIMER_LABEL_METER]      = "Beats and bars";
+       m_data[MAIN_TIMER_LABEL_QUANTIZER]  = "Live quantizer";
+       m_data[MAIN_TIMER_LABEL_MULTIPLIER] = "Beat multiplier";
+       m_data[MAIN_TIMER_LABEL_DIVIDER]    = "Beat divider";
+
+       m_data[MAIN_SEQUENCER_LABEL] = "Main sequencer";
+
+       m_data[MAIN_TRANSPORT_LABEL_REWIND]         = "Rewind";
+       m_data[MAIN_TRANSPORT_LABEL_PLAY]           = "Play/Stop";
+       m_data[MAIN_TRANSPORT_LABEL_RECTRIGGERMODE] = "Record-on-signal mode\n\nIf enabled, action "
+                                                     "and audio recording will start only when a signal (key press or audio) "
+                                                     "is detected.";
+       m_data[MAIN_TRANSPORT_LABEL_RECACTIONS]   = "Record actions";
+       m_data[MAIN_TRANSPORT_LABEL_RECINPUT]     = "Record audio";
+       m_data[MAIN_TRANSPORT_LABEL_RECINPUTMODE] = "Free loop-length mode\n\nIf enabled, the sequencer "
+                                                   "will adjust to the length of your first audio recording. "
+                                                   "Available only if there are no other audio samples in the "
+                                                   "project.";
+       m_data[MAIN_TRANSPORT_LABEL_METRONOME] = "Metronome";
+
+       m_data[MAIN_COLUMN_BUTTON]                  = "Edit column";
+       m_data[MAIN_COLUMN_BUTTON_ADDSAMPLECHANNEL] = "Add Sample channel";
+       m_data[MAIN_COLUMN_BUTTON_ADDMIDICHANNEL]   = "Add MIDI channel";
+       m_data[MAIN_COLUMN_BUTTON_REMOVE]           = "Remove";
+
+       m_data[MAIN_CHANNEL_NOSAMPLE]          = "-- no sample --";
+       m_data[MAIN_CHANNEL_SAMPLENOTFOUND]    = "* file not found! *";
+       m_data[MAIN_CHANNEL_LABEL_PLAY]        = "Play/stop";
+       m_data[MAIN_CHANNEL_LABEL_ARM]         = "Arm for recording";
+       m_data[MAIN_CHANNEL_LABEL_STATUS]      = "Progress bar";
+       m_data[MAIN_CHANNEL_LABEL_READACTIONS] = "Read actions\n\nToggles playback of pre-recorded "
+                                                "actions (key press, key release, ...).";
+       m_data[MAIN_CHANNEL_LABEL_MODEBOX]      = "Mode";
+       m_data[MAIN_CHANNEL_LABEL_MUTE]         = "Mute";
+       m_data[MAIN_CHANNEL_LABEL_SOLO]         = "Solo";
+       m_data[MAIN_CHANNEL_LABEL_FX]           = "Plug-ins";
+       m_data[MAIN_CHANNEL_LABEL_VOLUME]       = "Volume";
+       m_data[MAIN_CHANNEL_LABEL_MIDIACTIVITY] = "MIDI I/O activity\n\nNotifies MIDI messages sent (top) or "
+                                                 "received (bottom) by this channel.";
+
+       m_data[MAIN_CHANNEL_MENU_INPUTMONITOR]           = "Input monitor";
+       m_data[MAIN_CHANNEL_MENU_OVERDUBPROTECTION]      = "Overdub protection";
+       m_data[MAIN_CHANNEL_MENU_LOADSAMPLE]             = "Load new sample...";
+       m_data[MAIN_CHANNEL_MENU_EXPORTSAMPLE]           = "Export sample to file...";
+       m_data[MAIN_CHANNEL_MENU_KEYBOARDINPUT]          = "Setup keyboard input...";
+       m_data[MAIN_CHANNEL_MENU_MIDIINPUT]              = "Setup MIDI input...";
+       m_data[MAIN_CHANNEL_MENU_MIDIOUTPUT]             = "Setup MIDI output...";
+       m_data[MAIN_CHANNEL_MENU_EDITSAMPLE]             = "Edit sample...";
+       m_data[MAIN_CHANNEL_MENU_EDITACTIONS]            = "Edit actions...";
+       m_data[MAIN_CHANNEL_MENU_CLEARACTIONS]           = "Clear actions";
+       m_data[MAIN_CHANNEL_MENU_CLEARACTIONS_ALL]       = "All";
+       m_data[MAIN_CHANNEL_MENU_CLEARACTIONS_VOLUME]    = "Volume";
+       m_data[MAIN_CHANNEL_MENU_CLEARACTIONS_STARTSTOP] = "Start/Stop";
+       m_data[MAIN_CHANNEL_MENU_RENAME]                 = "Rename";
+       m_data[MAIN_CHANNEL_MENU_CLONE]                  = "Clone";
+       m_data[MAIN_CHANNEL_MENU_FREE]                   = "Free";
+       m_data[MAIN_CHANNEL_MENU_DELETE]                 = "Delete";
+
+       m_data[MISSINGASSETS_INTRO]      = "This project contains missing assets.";
+       m_data[MISSINGASSETS_AUDIOFILES] = "Audio files not found in the project folder:";
+       m_data[MISSINGASSETS_PLUGINS]    = "Audio plug-ins not found globally:";
+
+       m_data[PLUGINCHOOSER_TITLE]               = "Available plugins";
+       m_data[PLUGINCHOOSER_HEADER]              = "NAME\tMANUFACTURER\tCATEGORY\tFORMAT\tUID";
+       m_data[PLUGINCHOOSER_SORTBY]              = "Sort by";
+       m_data[PLUGINCHOOSER_SORTBY_NAME]         = "Name";
+       m_data[PLUGINCHOOSER_SORTBY_CATEGORY]     = "Category";
+       m_data[PLUGINCHOOSER_SORTBY_MANIFACTURER] = "Manifacturer";
+       m_data[PLUGINCHOOSER_SORTBY_FORMAT]       = "Format";
+
+       m_data[PLUGINLIST_TITLE_MASTEROUT] = "Master Out Plug-ins";
+       m_data[PLUGINLIST_TITLE_MASTERIN]  = "Master In Plug-ins";
+       m_data[PLUGINLIST_TITLE_CHANNEL]   = "Channel Plug-ins";
+       m_data[PLUGINLIST_ADDPLUGIN]       = "-- add new plugin --";
+       m_data[PLUGINLIST_NOPROGRAMS]      = "-- no programs --";
+
+       m_data[CHANNELNAME_TITLE] = "New channel name";
+
+       m_data[KEYGRABBER_TITLE] = "Key configuration";
+       m_data[KEYGRABBER_BODY]  = "Press a key.\n\nCurrent binding: ";
+
+       m_data[SAMPLEEDITOR_TITLE]                = "Sample Editor";
+       m_data[SAMPLEEDITOR_RELOAD]               = "Reload";
+       m_data[SAMPLEEDITOR_LOOP]                 = "Loop";
+       m_data[SAMPLEEDITOR_INFO]                 = "File: {}\nSize: {} frames\nDuration {} seconds\nBit depth: {}\nFrequency: {} Hz";
+       m_data[SAMPLEEDITOR_PAN]                  = "Pan";
+       m_data[SAMPLEEDITOR_PITCH]                = "Pitch";
+       m_data[SAMPLEEDITOR_PITCH_TOBAR]          = "To bar";
+       m_data[SAMPLEEDITOR_PITCH_TOSONG]         = "To song";
+       m_data[SAMPLEEDITOR_RANGE]                = "Range";
+       m_data[SAMPLEEDITOR_SHIFT]                = "Shift";
+       m_data[SAMPLEEDITOR_VOLUME]               = "Volume";
+       m_data[SAMPLEEDITOR_TOOLS_CUT]            = "Cut";
+       m_data[SAMPLEEDITOR_TOOLS_COPY]           = "Copy";
+       m_data[SAMPLEEDITOR_TOOLS_PASTE]          = "Paste";
+       m_data[SAMPLEEDITOR_TOOLS_TRIM]           = "Trim";
+       m_data[SAMPLEEDITOR_TOOLS_SILENCE]        = "Silence";
+       m_data[SAMPLEEDITOR_TOOLS_REVERSE]        = "Reverse";
+       m_data[SAMPLEEDITOR_TOOLS_NORMALIZE]      = "Normalize";
+       m_data[SAMPLEEDITOR_TOOLS_FADE_IN]        = "Fade in";
+       m_data[SAMPLEEDITOR_TOOLS_FADE_OUT]       = "Fade out";
+       m_data[SAMPLEEDITOR_TOOLS_SMOOTH_EDGES]   = "Smooth edges";
+       m_data[SAMPLEEDITOR_TOOLS_SET_BEGIN_END]  = "Set begin/end here";
+       m_data[SAMPLEEDITOR_TOOLS_TO_NEW_CHANNEL] = "Copy to new channel";
+
+       m_data[ACTIONEDITOR_TITLE]             = "Action Editor";
+       m_data[ACTIONEDITOR_VOLUME]            = "Volume";
+       m_data[ACTIONEDITOR_KEYPRESS]          = "Key press";
+       m_data[ACTIONEDITOR_KEYRELEASE]        = "Key release";
+       m_data[ACTIONEDITOR_STOPSAMPLE]        = "Stop sample";
+       m_data[ACTIONEDITOR_STARTSTOP]         = "Start/stop";
+       m_data[ACTIONEDITOR_STARTSTOPDISABLED] = "Start/stop (disabled)";
+       m_data[ACTIONEDITOR_VELOCITY]          = "Velocity";
+       m_data[ACTIONEDITOR_LABEL_ACTIONTYPE]  = "Action type to add";
+
+       m_data[BROWSER_SHOWHIDDENFILES] = "Show hidden files";
+       m_data[BROWSER_OPENPROJECT]     = "Open project";
+       m_data[BROWSER_SAVEPROJECT]     = "Save project";
+       m_data[BROWSER_OPENSAMPLE]      = "Open sample";
+       m_data[BROWSER_SAVESAMPLE]      = "Save sample";
+       m_data[BROWSER_OPENPLUGINSDIR]  = "Open plug-ins directory";
+
+       m_data[MIDIINPUT_MASTER_TITLE]           = "MIDI Input Setup (global)";
+       m_data[MIDIINPUT_MASTER_ENABLE]          = "Enable MIDI input";
+       m_data[MIDIINPUT_MASTER_LEARN_REWIND]    = "Rewind";
+       m_data[MIDIINPUT_MASTER_LEARN_PLAYSTOP]  = "Play/stop";
+       m_data[MIDIINPUT_MASTER_LEARN_ACTIONREC] = "Action recording";
+       m_data[MIDIINPUT_MASTER_LEARN_INPUTREC]  = "Input recording";
+       m_data[MIDIINPUT_MASTER_LEARN_METRONOME] = "metronome";
+       m_data[MIDIINPUT_MASTER_LEARN_INVOLUME]  = "Input volume";
+       m_data[MIDIINPUT_MASTER_LEARN_OUTVOLUME] = "Output volume";
+       m_data[MIDIINPUT_MASTER_LEARN_SEQDOUBLE] = "Sequencer Ã—2";
+       m_data[MIDIINPUT_MASTER_LEARN_SEQHALF]   = "Sequencer Ã·2";
+
+       m_data[MIDIINPUT_CHANNEL_TITLE]             = "MIDI Input Setup";
+       m_data[MIDIINPUT_CHANNEL_ENABLE]            = "Enable MIDI input";
+       m_data[MIDIINPUT_CHANNEL_VELOCITYDRIVESVOL] = "Velocity drives volume (Sample Channels)";
+       m_data[MIDIINPUT_CHANNEL_LEARN_CHANNEL]     = "Channel";
+       m_data[MIDIINPUT_CHANNEL_LEARN_KEYPRESS]    = "Key press";
+       m_data[MIDIINPUT_CHANNEL_LEARN_KEYREL]      = "Key release";
+       m_data[MIDIINPUT_CHANNEL_LEARN_KEYKILL]     = "Key kill";
+       m_data[MIDIINPUT_CHANNEL_LEARN_ARM]         = "Arm";
+       m_data[MIDIINPUT_CHANNEL_LEARN_MUTE]        = "Mute";
+       m_data[MIDIINPUT_CHANNEL_LEARN_SOLO]        = "Solo";
+       m_data[MIDIINPUT_CHANNEL_LEARN_VOLUME]      = "Volume";
+       m_data[MIDIINPUT_CHANNEL_LEARN_PITCH]       = "Pitch";
+       m_data[MIDIINPUT_CHANNEL_LEARN_READACTIONS] = "Read actions";
+
+       m_data[MIDIOUTPUT_CHANNEL_TITLE]            = "Midi Output Setup";
+       m_data[MIDIOUTPUT_CHANNEL_ENABLE]           = "Enable MIDI output";
+       m_data[MIDIOUTPUT_CHANNEL_ENABLE_LIGHTNING] = "Enable MIDI lightning output";
+       m_data[MIDIOUTPUT_CHANNEL_LEARN_PLAYING]    = "Playing";
+       m_data[MIDIOUTPUT_CHANNEL_LEARN_MUTE]       = "Mute";
+       m_data[MIDIOUTPUT_CHANNEL_LEARN_SOLO]       = "Solo";
+
+       m_data[ABOUT_TITLE] = "About Giada";
+       m_data[ABOUT_BODY]  = "Version {} ({} build) {}\n\n"
+                            "Developed by Monocasual Laboratories\n\n"
+                            "Released under the terms of the GNU General\n"
+                            "Public License (GPL v3)\n\n"
+                            "News, infos, contacts and documentation:\n"
+                            "www.giadamusic.com";
+       m_data[ABOUT_BODY_VST] = "VST Plug-In Technology by Steinberg\n"
+                                "VST is a trademark of Steinberg\nMedia Technologies GmbH";
+
+       m_data[CONFIG_TITLE]        = "Configuration";
+       m_data[CONFIG_RESTARTGIADA] = "Restart Giada for the changes to take effect.";
+
+       m_data[CONFIG_AUDIO_TITLE]                 = "Audio";
+       m_data[CONFIG_AUDIO_SYSTEM]                = "System";
+       m_data[CONFIG_AUDIO_BUFFERSIZE]            = "Buffer size";
+       m_data[CONFIG_AUDIO_SAMPLERATE]            = "Sample rate";
+       m_data[CONFIG_AUDIO_OUTPUTDEVICE]          = "Output device";
+       m_data[CONFIG_AUDIO_OUTPUTCHANNELS]        = "Output channels";
+       m_data[CONFIG_AUDIO_LIMITOUTPUT]           = "Limit output";
+       m_data[CONFIG_AUDIO_INPUTDEVICE]           = "Input device";
+       m_data[CONFIG_AUDIO_INPUTCHANNELS]         = "Input channels";
+       m_data[CONFIG_AUDIO_RECTHRESHOLD]          = "Rec threshold (dB)";
+       m_data[CONFIG_AUDIO_ENABLEINPUT]           = "Enable Input";
+       m_data[CONFIG_AUDIO_RESAMPLING]            = "Resampling";
+       m_data[CONFIG_AUDIO_RESAMPLING_SINCBEST]   = "Sinc best quality (very slow)";
+       m_data[CONFIG_AUDIO_RESAMPLING_SINCMEDIUM] = "Sinc medium quality (slow)";
+       m_data[CONFIG_AUDIO_RESAMPLING_SINCBASIC]  = "Sinc basic quality (medium)";
+       m_data[CONFIG_AUDIO_RESAMPLING_ZEROORDER]  = "Zero Order Hold (fast)";
+       m_data[CONFIG_AUDIO_RESAMPLING_LINEAR]     = "Linear (very fast)";
+       m_data[CONFIG_AUDIO_NODEVICESFOUND]        = "-- no devices found --";
+
+       m_data[CONFIG_MIDI_TITLE]           = "MIDI";
+       m_data[CONFIG_MIDI_SYSTEM]          = "System";
+       m_data[CONFIG_MIDI_OUTPUTPORT]      = "Output port";
+       m_data[CONFIG_MIDI_INPUTPORT]       = "Input port";
+       m_data[CONFIG_MIDI_NOPORTSFOUND]    = "-- no ports found --";
+       m_data[CONFIG_MIDI_OUTPUTMIDIMAP]   = "Output MIDI Map";
+       m_data[CONFIG_MIDI_NOMIDIMAPSFOUND] = "(no MIDI maps available)";
+       m_data[CONFIG_MIDI_SYNC]            = "Sync";
+       m_data[CONFIG_MIDI_LABEL_ENABLEOUT] = "Enable Output port";
+       m_data[CONFIG_MIDI_LABEL_ENABLEIN]  = "Enable Input port";
+
+       m_data[CONFIG_BEHAVIORS_TITLE]                      = "Behaviors";
+       m_data[CONFIG_BEHAVIORS_CHANSSTOPONSEQHALT]         = "Dynamic channels stop immediately when the sequencer is halted";
+       m_data[CONFIG_BEHAVIORS_TREATRECSASLOOPS]           = "Treat one shot channels with actions as loops";
+       m_data[CONFIG_BEHAVIORS_INPUTMONITORDEFAULTON]      = "New sample channels have input monitor on by default";
+       m_data[CONFIG_BEHAVIORS_OVERDUBPROTECTIONDEFAULTON] = "New sample channels have overdub protection on by default";
+
+       m_data[CONFIG_BINDINGS_TITLE]         = "Key Bindings";
+       m_data[CONFIG_BINDINGS_PLAY]          = "Play";
+       m_data[CONFIG_BINDINGS_REWIND]        = "Rewind";
+       m_data[CONFIG_BINDINGS_RECORDACTIONS] = "Record actions";
+       m_data[CONFIG_BINDINGS_RECORDAUDIO]   = "Record audio";
+       m_data[CONFIG_BINDINGS_EXIT]          = "Exit";
+
+       m_data[CONFIG_MISC_TITLE]                  = "Misc";
+       m_data[CONFIG_MISC_DEBUGMESSAGES]          = "Debug messages";
+       m_data[CONFIG_MISC_DEBUGMESSAGES_DISABLED] = "Disabled";
+       m_data[CONFIG_MISC_DEBUGMESSAGES_TOSTDOUT] = "To standard output";
+       m_data[CONFIG_MISC_DEBUGMESSAGES_TOFILE]   = "To file";
+       m_data[CONFIG_MISC_TOOLTIPS]               = "Tooltips";
+       m_data[CONFIG_MISC_TOOLTIPS_DISABLED]      = "Disabled";
+       m_data[CONFIG_MISC_TOOLTIPS_ENABLED]       = "Enabled";
+       m_data[CONFIG_MISC_LANGUAGE]               = "Language file";
+       m_data[CONFIG_MISC_NOLANGUAGESFOUND]       = "-- no language files found --";
+
+       m_data[CONFIG_PLUGINS_TITLE]       = "Plug-ins";
+       m_data[CONFIG_PLUGINS_FOLDER]      = "Plug-ins folder";
+       m_data[CONFIG_PLUGINS_SCANNING]    = "Scan in progress ({}%). Please wait...";
+       m_data[CONFIG_PLUGINS_SCAN]        = "Scan ({} found)";
+       m_data[CONFIG_PLUGINS_INVALIDPATH] = "Invalid path.";
+}
+
+const char* LangMap::get(const std::string& key) const
+{
+       if (m_data.count(key) == 0)
+               return m_default.c_str();
+       return m_data.at(key).c_str();
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+LangMapper::LangMapper()
+{
+       m_mapsPath = u::fs::getLangMapsPath();
+}
+
+/* -------------------------------------------------------------------------- */
+
+void LangMapper::init()
+{
+       Mapper::init();
+       u::log::print("[LangMapper::init] total langmaps found: %d\n", m_mapFiles.size());
+}
+
+/* -------------------------------------------------------------------------- */
+
+int LangMapper::read(const std::string& file)
+{
+       std::optional<nl::json> res = Mapper::read(file);
+       if (!res)
+               return G_FILE_UNREADABLE;
+
+       m_map.m_data = res.value().get<LangMap::Data>();
+
+       return G_FILE_OK;
+}
+
+/* -------------------------------------------------------------------------- */
+
+const char* LangMapper::get(const std::string& s) const
+{
+       return m_map.get(s);
+}
+} // namespace giada::v
diff --git a/src/gui/langMapper.h b/src/gui/langMapper.h
new file mode 100644 (file)
index 0000000..da97b60
--- /dev/null
@@ -0,0 +1,375 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_LANGMAPPER_H
+#define G_LANGMAPPER_H
+
+#include "mapper.h"
+#include <nlohmann/json.hpp>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace giada::v
+{
+class LangMap
+{
+public:
+       friend class LangMapper;
+
+       using Data = std::unordered_map<std::string, std::string>;
+
+       static constexpr auto COMMON_OK         = "common_ok";
+       static constexpr auto COMMON_CANCEL     = "common_cancel";
+       static constexpr auto COMMON_YES        = "common_yes";
+       static constexpr auto COMMON_NO         = "common_no";
+       static constexpr auto COMMON_OFF        = "common_off";
+       static constexpr auto COMMON_SELECT     = "common_select";
+       static constexpr auto COMMON_LOAD       = "common_load";
+       static constexpr auto COMMON_SAVE       = "common_save";
+       static constexpr auto COMMON_WARNING    = "common_warning";
+       static constexpr auto COMMON_CLOSE      = "common_close";
+       static constexpr auto COMMON_ADD        = "common_add";
+       static constexpr auto COMMON_CLEAR      = "common_clear";
+       static constexpr auto COMMON_RELOAD     = "common_reload";
+       static constexpr auto COMMON_RESET      = "common_reset";
+       static constexpr auto COMMON_ZOOMIN     = "common_zoomIn";
+       static constexpr auto COMMON_ZOOMOUT    = "common_zoomOut";
+       static constexpr auto COMMON_GRIDRES    = "common_gridRes";
+       static constexpr auto COMMON_SNAPTOGRID = "common_snapToGrid";
+       static constexpr auto COMMON_BIND       = "common_bind";
+       static constexpr auto COMMON_LEARN      = "common_learn";
+       static constexpr auto COMMON_NOTSET     = "common_notSet";
+       static constexpr auto COMMON_NONE       = "common_none";
+
+       static constexpr auto MESSAGE_MAIN_FREEALLSAMPLES           = "message_main_freeAllSamples";
+       static constexpr auto MESSAGE_MAIN_CLEARALLACTIONS          = "message_main_clearAllActions";
+       static constexpr auto MESSAGE_MAIN_CLEARALLVOLUMEACTIONS    = "message_main_clearAllVolumeActions";
+       static constexpr auto MESSAGE_MAIN_CLEARALLSTARTSTOPACTIONS = "message_main_clearAllStartStopActions";
+       static constexpr auto MESSAGE_MAIN_CLOSEPROJECT             = "message_main_closeProject";
+
+       static constexpr auto MESSAGE_INIT_WRONGSYSTEM = "message_init_wrongSystem";
+       static constexpr auto MESSAGE_INIT_QUITGIADA   = "message_init_quitGiada";
+
+       static constexpr auto MESSAGE_CHANNEL_MULTICHANNOTSUPPORTED = "message_channel_multiChanNotSupported";
+       static constexpr auto MESSAGE_CHANNEL_CANTREADSAMPLE        = "message_channel_cantReadSample";
+       static constexpr auto MESSAGE_CHANNEL_PATHTOOLONG           = "message_channel_pathTooLong";
+       static constexpr auto MESSAGE_CHANNEL_NOFILESPECIFIED       = "message_channel_noFileSpecified";
+       static constexpr auto MESSAGE_CHANNEL_LOADINGSAMPLES        = "message_channel_loadingSamples";
+       static constexpr auto MESSAGE_CHANNEL_LOADINGSAMPLESERROR   = "message_channel_loadingSamplesError";
+       static constexpr auto MESSAGE_CHANNEL_DELETE                = "message_channel_delete";
+       static constexpr auto MESSAGE_CHANNEL_FREE                  = "message_channel_free";
+
+       static constexpr auto MESSAGE_STORAGE_PATCHUNREADABLE    = "message_storage_patchUnreadable";
+       static constexpr auto MESSAGE_STORAGE_PATCHINVALID       = "message_storage_patchInvalid";
+       static constexpr auto MESSAGE_STORAGE_PATCHUNSUPPORTED   = "message_storage_patchUnsupported";
+       static constexpr auto MESSAGE_STORAGE_PROJECTEXISTS      = "message_storage_projectExists";
+       static constexpr auto MESSAGE_STORAGE_LOADINGPROJECT     = "message_storage_loadingProject";
+       static constexpr auto MESSAGE_STORAGE_LOADINGSAMPLE      = "message_storage_loadingSample";
+       static constexpr auto MESSAGE_STORAGE_SAVINGPROJECT      = "message_storage_savingProject";
+       static constexpr auto MESSAGE_STORAGE_SAVINGPROJECTERROR = "message_storage_savingProjectError";
+       static constexpr auto MESSAGE_STORAGE_CHOOSEPROJECTNAME  = "message_storage_chooseProjectName";
+       static constexpr auto MESSAGE_STORAGE_CHOOSEFILENAME     = "message_storage_chooseFileName";
+       static constexpr auto MESSAGE_STORAGE_FILEEXISTS         = "message_storage_fileExists";
+       static constexpr auto MESSAGE_STORAGE_SAVINGFILEERROR    = "message_storage_savingFileError";
+
+       static constexpr auto MAIN_MENU_FILE                 = "main_menu_file";
+       static constexpr auto MAIN_MENU_FILE_OPENPROJECT     = "main_menu_file_openProject";
+       static constexpr auto MAIN_MENU_FILE_SAVEPROJECT     = "main_menu_file_saveProject";
+       static constexpr auto MAIN_MENU_FILE_CLOSEPROJECT    = "main_menu_file_closeProject";
+       static constexpr auto MAIN_MENU_FILE_QUIT            = "main_menu_file_quit";
+       static constexpr auto MAIN_MENU_EDIT                 = "main_menu_edit";
+       static constexpr auto MAIN_MENU_EDIT_FREEALLSAMPLES  = "main_menu_edit_freeAllSamples";
+       static constexpr auto MAIN_MENU_EDIT_CLEARALLACTIONS = "main_menu_edit_clearAllActions";
+       static constexpr auto MAIN_MENU_EDIT_SETUPMIDIINPUT  = "main_menu_edit_setupMidiInput";
+       static constexpr auto MAIN_MENU_CONFIG               = "main_menu_config";
+       static constexpr auto MAIN_MENU_ABOUT                = "main_menu_about";
+
+       static constexpr auto MAIN_IO_LABEL_OUTMETER = "main_IO_label_outMeter";
+       static constexpr auto MAIN_IO_LABEL_INMETER  = "main_IO_label_inMeter";
+       static constexpr auto MAIN_IO_LABEL_OUTVOL   = "main_IO_label_outVol";
+       static constexpr auto MAIN_IO_LABEL_INVOL    = "main_IO_label_inVol";
+       static constexpr auto MAIN_IO_LABEL_INTOOUT  = "main_IO_label_inToOut";
+       static constexpr auto MAIN_IO_LABEL_FXOUT    = "main_IO_label_fxOut";
+       static constexpr auto MAIN_IO_LABEL_FXIN     = "main_IO_label_fxIn";
+
+       static constexpr auto MAIN_TIMER_LABEL_BPM        = "main_mainTimer_label_bpm";
+       static constexpr auto MAIN_TIMER_LABEL_METER      = "main_mainTimer_label_meter";
+       static constexpr auto MAIN_TIMER_LABEL_QUANTIZER  = "main_mainTimer_label_quantizer";
+       static constexpr auto MAIN_TIMER_LABEL_MULTIPLIER = "main_mainTimer_label_multiplier";
+       static constexpr auto MAIN_TIMER_LABEL_DIVIDER    = "main_mainTimer_label_divider";
+
+       static constexpr auto MAIN_SEQUENCER_LABEL = "main_sequencer_label";
+
+       static constexpr auto MAIN_TRANSPORT_LABEL_REWIND         = "main_transport_label_rewind";
+       static constexpr auto MAIN_TRANSPORT_LABEL_PLAY           = "main_transport_label_play";
+       static constexpr auto MAIN_TRANSPORT_LABEL_RECTRIGGERMODE = "main_transport_label_recTriggerMode";
+       static constexpr auto MAIN_TRANSPORT_LABEL_RECACTIONS     = "main_transport_label_recActions";
+       static constexpr auto MAIN_TRANSPORT_LABEL_RECINPUT       = "main_transport_label_recInput";
+       static constexpr auto MAIN_TRANSPORT_LABEL_RECINPUTMODE   = "main_transport_label_recInputMode";
+       static constexpr auto MAIN_TRANSPORT_LABEL_METRONOME      = "main_transport_label_metronome";
+
+       static constexpr auto MAIN_COLUMN_BUTTON                  = "main_column_button";
+       static constexpr auto MAIN_COLUMN_BUTTON_ADDSAMPLECHANNEL = "main_column_button_addSampleChannel";
+       static constexpr auto MAIN_COLUMN_BUTTON_ADDMIDICHANNEL   = "main_column_button_addMidiChannel";
+       static constexpr auto MAIN_COLUMN_BUTTON_REMOVE           = "main_column_button_remove";
+
+       static constexpr auto MAIN_CHANNEL_NOSAMPLE           = "main_channel_noSample";
+       static constexpr auto MAIN_CHANNEL_SAMPLENOTFOUND     = "main_channel_sampleNotFound";
+       static constexpr auto MAIN_CHANNEL_LABEL_PLAY         = "main_channel_label_play";
+       static constexpr auto MAIN_CHANNEL_LABEL_ARM          = "main_channel_label_arm";
+       static constexpr auto MAIN_CHANNEL_LABEL_STATUS       = "main_channel_label_status";
+       static constexpr auto MAIN_CHANNEL_LABEL_READACTIONS  = "main_channel_label_readActions";
+       static constexpr auto MAIN_CHANNEL_LABEL_MODEBOX      = "main_channel_label_modeBox";
+       static constexpr auto MAIN_CHANNEL_LABEL_MUTE         = "main_channel_label_mute";
+       static constexpr auto MAIN_CHANNEL_LABEL_SOLO         = "main_channel_label_solo";
+       static constexpr auto MAIN_CHANNEL_LABEL_FX           = "main_channel_label_fx";
+       static constexpr auto MAIN_CHANNEL_LABEL_VOLUME       = "main_channel_label_volume";
+       static constexpr auto MAIN_CHANNEL_LABEL_MIDIACTIVITY = "main_channel_label_midiActivity";
+
+       static constexpr auto MAIN_CHANNEL_MENU_INPUTMONITOR           = "main_channel_menu_inputMonitor";
+       static constexpr auto MAIN_CHANNEL_MENU_OVERDUBPROTECTION      = "main_channel_menu_overdubProtection";
+       static constexpr auto MAIN_CHANNEL_MENU_LOADSAMPLE             = "main_channel_menu_loadSample";
+       static constexpr auto MAIN_CHANNEL_MENU_EXPORTSAMPLE           = "main_channel_menu_exportSample";
+       static constexpr auto MAIN_CHANNEL_MENU_KEYBOARDINPUT          = "main_channel_menu_keyboardInput";
+       static constexpr auto MAIN_CHANNEL_MENU_MIDIINPUT              = "main_channel_menu_midiInput";
+       static constexpr auto MAIN_CHANNEL_MENU_MIDIOUTPUT             = "main_channel_menu_midiOutput";
+       static constexpr auto MAIN_CHANNEL_MENU_EDITSAMPLE             = "main_channel_menu_editSample";
+       static constexpr auto MAIN_CHANNEL_MENU_EDITACTIONS            = "main_channel_menu_editActions";
+       static constexpr auto MAIN_CHANNEL_MENU_CLEARACTIONS           = "main_channel_menu_clearActions";
+       static constexpr auto MAIN_CHANNEL_MENU_CLEARACTIONS_ALL       = "main_channel_menu_clearActions_all";
+       static constexpr auto MAIN_CHANNEL_MENU_CLEARACTIONS_VOLUME    = "main_channel_menu_clearActions_volume";
+       static constexpr auto MAIN_CHANNEL_MENU_CLEARACTIONS_STARTSTOP = "main_channel_menu_clearActions_startStop";
+       static constexpr auto MAIN_CHANNEL_MENU_RENAME                 = "main_channel_menu_rename";
+       static constexpr auto MAIN_CHANNEL_MENU_CLONE                  = "main_channel_menu_clone";
+       static constexpr auto MAIN_CHANNEL_MENU_FREE                   = "main_channel_menu_free";
+       static constexpr auto MAIN_CHANNEL_MENU_DELETE                 = "main_channel_menu_delete";
+
+       static constexpr auto MISSINGASSETS_INTRO      = "missingAssets_intro";
+       static constexpr auto MISSINGASSETS_AUDIOFILES = "missingAssets_audioFiles";
+       static constexpr auto MISSINGASSETS_PLUGINS    = "missingAssets_plugIns";
+
+       static constexpr auto PLUGINCHOOSER_TITLE               = "pluginChooser_title";
+       static constexpr auto PLUGINCHOOSER_HEADER              = "pluginChooser_header";
+       static constexpr auto PLUGINCHOOSER_SORTBY              = "pluginChooser_sortBy";
+       static constexpr auto PLUGINCHOOSER_SORTBY_NAME         = "pluginChooser_sortBy_name";
+       static constexpr auto PLUGINCHOOSER_SORTBY_CATEGORY     = "pluginChooser_sortBy_category";
+       static constexpr auto PLUGINCHOOSER_SORTBY_MANIFACTURER = "pluginChooser_sortBy_manifacturer";
+       static constexpr auto PLUGINCHOOSER_SORTBY_FORMAT       = "pluginChooser_sortBy_format";
+
+       static constexpr auto PLUGINLIST_TITLE_MASTEROUT = "pluginList_title_masterOut";
+       static constexpr auto PLUGINLIST_TITLE_MASTERIN  = "pluginList_title_masterIn";
+       static constexpr auto PLUGINLIST_TITLE_CHANNEL   = "pluginList_title_channel";
+       static constexpr auto PLUGINLIST_ADDPLUGIN       = "pluginList_addPlugin";
+       static constexpr auto PLUGINLIST_NOPROGRAMS      = "pluginList_noPrograms";
+
+       static constexpr auto CHANNELNAME_TITLE = "channelName_title";
+
+       static constexpr auto KEYGRABBER_TITLE = "keyGrabber_title";
+       static constexpr auto KEYGRABBER_BODY  = "keyGrabber_body";
+
+       static constexpr auto SAMPLEEDITOR_TITLE                = "sampleEditor_title";
+       static constexpr auto SAMPLEEDITOR_RELOAD               = "sampleEditor_reload";
+       static constexpr auto SAMPLEEDITOR_LOOP                 = "sampleEditor_loop";
+       static constexpr auto SAMPLEEDITOR_INFO                 = "sampleEditor_info";
+       static constexpr auto SAMPLEEDITOR_PAN                  = "sampleEditor_pan";
+       static constexpr auto SAMPLEEDITOR_PITCH                = "sampleEditor_pitch";
+       static constexpr auto SAMPLEEDITOR_PITCH_TOBAR          = "sampleEditor_pitch_toBar";
+       static constexpr auto SAMPLEEDITOR_PITCH_TOSONG         = "sampleEditor_pitch_toSong";
+       static constexpr auto SAMPLEEDITOR_RANGE                = "sampleEditor_range";
+       static constexpr auto SAMPLEEDITOR_SHIFT                = "sampleEditor_shift";
+       static constexpr auto SAMPLEEDITOR_VOLUME               = "sampleEditor_volume";
+       static constexpr auto SAMPLEEDITOR_TOOLS_CUT            = "sampleEditor_tools_cut";
+       static constexpr auto SAMPLEEDITOR_TOOLS_COPY           = "sampleEditor_tools_copy";
+       static constexpr auto SAMPLEEDITOR_TOOLS_PASTE          = "sampleEditor_tools_paste";
+       static constexpr auto SAMPLEEDITOR_TOOLS_TRIM           = "sampleEditor_tools_trim";
+       static constexpr auto SAMPLEEDITOR_TOOLS_SILENCE        = "sampleEditor_tools_silence";
+       static constexpr auto SAMPLEEDITOR_TOOLS_REVERSE        = "sampleEditor_tools_reverse";
+       static constexpr auto SAMPLEEDITOR_TOOLS_NORMALIZE      = "sampleEditor_tools_normalize";
+       static constexpr auto SAMPLEEDITOR_TOOLS_FADE_IN        = "sampleEditor_tools_fadeIn";
+       static constexpr auto SAMPLEEDITOR_TOOLS_FADE_OUT       = "sampleEditor_tools_fadeOut";
+       static constexpr auto SAMPLEEDITOR_TOOLS_SMOOTH_EDGES   = "sampleEditor_tools_smoothEdgdes";
+       static constexpr auto SAMPLEEDITOR_TOOLS_SET_BEGIN_END  = "sampleEditor_tools_setBeginEnd";
+       static constexpr auto SAMPLEEDITOR_TOOLS_TO_NEW_CHANNEL = "sampleEditor_tools_toNewChannel";
+
+       static constexpr auto ACTIONEDITOR_TITLE             = "actionEditor_title";
+       static constexpr auto ACTIONEDITOR_VOLUME            = "actionEditor_volume";
+       static constexpr auto ACTIONEDITOR_KEYPRESS          = "actionEditor_keyPress";
+       static constexpr auto ACTIONEDITOR_KEYRELEASE        = "actionEditor_keyRelease";
+       static constexpr auto ACTIONEDITOR_STOPSAMPLE        = "actionEditor_stopSample";
+       static constexpr auto ACTIONEDITOR_STARTSTOP         = "actionEditor_startStop";
+       static constexpr auto ACTIONEDITOR_STARTSTOPDISABLED = "actionEditor_startStopDisabled";
+       static constexpr auto ACTIONEDITOR_VELOCITY          = "actionEditor_velocity";
+       static constexpr auto ACTIONEDITOR_LABEL_ACTIONTYPE  = "actionEditor_label_actionType";
+
+       static constexpr auto BROWSER_SHOWHIDDENFILES = "browser_showHiddenFiles";
+       static constexpr auto BROWSER_OPENPROJECT     = "browser_openProject";
+       static constexpr auto BROWSER_SAVEPROJECT     = "browser_saveProject";
+       static constexpr auto BROWSER_OPENSAMPLE      = "browser_openSample";
+       static constexpr auto BROWSER_SAVESAMPLE      = "browser_saveSample";
+       static constexpr auto BROWSER_OPENPLUGINSDIR  = "browser_openPluginsDir";
+
+       static constexpr auto MIDIINPUT_MASTER_TITLE           = "midiInput_master_title";
+       static constexpr auto MIDIINPUT_MASTER_ENABLE          = "midiInput_master_enable";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_REWIND    = "midiInput_master_learn_rewind";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_PLAYSTOP  = "midiInput_master_learn_playStop";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_ACTIONREC = "midiInput_master_learn_actionRec";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_INPUTREC  = "midiInput_master_learn_inputRec";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_METRONOME = "midiInput_master_learn_metronome";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_INVOLUME  = "midiInput_master_learn_inVolume";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_OUTVOLUME = "midiInput_master_learn_outVolume";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_SEQDOUBLE = "midiInput_master_learn_seqDouble";
+       static constexpr auto MIDIINPUT_MASTER_LEARN_SEQHALF   = "midiInput_master_learn_seqHalf";
+
+       static constexpr auto MIDIINPUT_CHANNEL_TITLE             = "midiInput_channel_title";
+       static constexpr auto MIDIINPUT_CHANNEL_ENABLE            = "midiInput_channel_enable";
+       static constexpr auto MIDIINPUT_CHANNEL_VELOCITYDRIVESVOL = "midiInput_channel_learn_velocityDrivesVol";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_CHANNEL     = "midiInput_channel_learn_channel";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_KEYPRESS    = "midiInput_channel_learn_keyPress";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_KEYREL      = "midiInput_channel_learn_keyRel";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_KEYKILL     = "midiInput_channel_learn_keyKill";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_ARM         = "midiInput_channel_learn_arm";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_MUTE        = "midiInput_channel_learn_mute";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_SOLO        = "midiInput_channel_learn_solo";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_VOLUME      = "midiInput_channel_learn_volume";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_PITCH       = "midiInput_channel_learn_pitch";
+       static constexpr auto MIDIINPUT_CHANNEL_LEARN_READACTIONS = "midiInput_channel_learn_readActions";
+
+       static constexpr auto MIDIOUTPUT_CHANNEL_TITLE            = "midiOutput_channel_title";
+       static constexpr auto MIDIOUTPUT_CHANNEL_ENABLE           = "midiOutput_channel_enable";
+       static constexpr auto MIDIOUTPUT_CHANNEL_ENABLE_LIGHTNING = "midiOutput_channel_enableLightning";
+       static constexpr auto MIDIOUTPUT_CHANNEL_LEARN_PLAYING    = "midiOutput_channel_learn_playing";
+       static constexpr auto MIDIOUTPUT_CHANNEL_LEARN_MUTE       = "midiOutput_channel_learn_mute";
+       static constexpr auto MIDIOUTPUT_CHANNEL_LEARN_SOLO       = "midiOutput_channel_learn_solo";
+
+       static constexpr auto ABOUT_TITLE    = "about_title";
+       static constexpr auto ABOUT_BODY     = "about_body";
+       static constexpr auto ABOUT_BODY_VST = "about_body_vst";
+
+       static constexpr auto CONFIG_TITLE        = "config_title";
+       static constexpr auto CONFIG_RESTARTGIADA = "config_restartGiada";
+
+       static constexpr auto CONFIG_AUDIO_TITLE                 = "config_audio_title";
+       static constexpr auto CONFIG_AUDIO_SYSTEM                = "config_audio_system";
+       static constexpr auto CONFIG_AUDIO_BUFFERSIZE            = "config_audio_bufferSize";
+       static constexpr auto CONFIG_AUDIO_SAMPLERATE            = "config_audio_sampleRate";
+       static constexpr auto CONFIG_AUDIO_OUTPUTDEVICE          = "config_audio_outputDevice";
+       static constexpr auto CONFIG_AUDIO_OUTPUTCHANNELS        = "config_audio_outputChannels";
+       static constexpr auto CONFIG_AUDIO_LIMITOUTPUT           = "config_audio_limitOutput";
+       static constexpr auto CONFIG_AUDIO_INPUTDEVICE           = "config_audio_inputDevice";
+       static constexpr auto CONFIG_AUDIO_INPUTCHANNELS         = "config_audio_inputChannels";
+       static constexpr auto CONFIG_AUDIO_RECTHRESHOLD          = "config_audio_recThreshold";
+       static constexpr auto CONFIG_AUDIO_ENABLEINPUT           = "config_audio_enableInput";
+       static constexpr auto CONFIG_AUDIO_RESAMPLING            = "config_audio_reseampling";
+       static constexpr auto CONFIG_AUDIO_RESAMPLING_SINCBEST   = "config_audio_reseampling_sincBest";
+       static constexpr auto CONFIG_AUDIO_RESAMPLING_SINCMEDIUM = "config_audio_reseampling_sincMedium";
+       static constexpr auto CONFIG_AUDIO_RESAMPLING_SINCBASIC  = "config_audio_reseampling_sincBasic";
+       static constexpr auto CONFIG_AUDIO_RESAMPLING_ZEROORDER  = "config_audio_reseampling_zeroOrder";
+       static constexpr auto CONFIG_AUDIO_RESAMPLING_LINEAR     = "config_audio_reseampling_linear";
+       static constexpr auto CONFIG_AUDIO_NODEVICESFOUND        = "config_audio_noDevicesFound";
+
+       static constexpr auto CONFIG_MIDI_TITLE           = "config_midi_title";
+       static constexpr auto CONFIG_MIDI_SYSTEM          = "config_midi_system";
+       static constexpr auto CONFIG_MIDI_OUTPUTPORT      = "config_midi_outputPort";
+       static constexpr auto CONFIG_MIDI_INPUTPORT       = "config_midi_inputPort";
+       static constexpr auto CONFIG_MIDI_NOPORTSFOUND    = "config_midi_noPortsFound";
+       static constexpr auto CONFIG_MIDI_OUTPUTMIDIMAP   = "config_midi_outputMidiMap";
+       static constexpr auto CONFIG_MIDI_NOMIDIMAPSFOUND = "config_midi_noMidiMapsFound";
+       static constexpr auto CONFIG_MIDI_SYNC            = "config_midi_sync";
+       static constexpr auto CONFIG_MIDI_LABEL_ENABLEOUT = "config_midi_label_enableOut";
+       static constexpr auto CONFIG_MIDI_LABEL_ENABLEIN  = "config_midi_label_enableIn";
+
+       static constexpr auto CONFIG_BEHAVIORS_TITLE                      = "config_behaviors_title";
+       static constexpr auto CONFIG_BEHAVIORS_CHANSSTOPONSEQHALT         = "config_behaviors_chansStopOnSeqHalt";
+       static constexpr auto CONFIG_BEHAVIORS_TREATRECSASLOOPS           = "config_behaviors_treatRecsAsLoops";
+       static constexpr auto CONFIG_BEHAVIORS_INPUTMONITORDEFAULTON      = "config_behaviors_inputMonitorDefaultOn";
+       static constexpr auto CONFIG_BEHAVIORS_OVERDUBPROTECTIONDEFAULTON = "config_behaviors_overdubProtectionDefaultOn";
+
+       static constexpr auto CONFIG_BINDINGS_TITLE         = "config_bindings_title";
+       static constexpr auto CONFIG_BINDINGS_PLAY          = "config_bindings_play";
+       static constexpr auto CONFIG_BINDINGS_REWIND        = "config_bindings_rewind";
+       static constexpr auto CONFIG_BINDINGS_RECORDACTIONS = "config_bindings_recordActions";
+       static constexpr auto CONFIG_BINDINGS_RECORDAUDIO   = "config_bindings_recordAudio";
+       static constexpr auto CONFIG_BINDINGS_EXIT          = "config_bindings_exit";
+
+       static constexpr auto CONFIG_MISC_TITLE                  = "config_misc_title";
+       static constexpr auto CONFIG_MISC_DEBUGMESSAGES          = "config_misc_debugMessages";
+       static constexpr auto CONFIG_MISC_DEBUGMESSAGES_DISABLED = "config_misc_debugMessages_disabled";
+       static constexpr auto CONFIG_MISC_DEBUGMESSAGES_TOSTDOUT = "config_misc_debugMessages_toStdOut";
+       static constexpr auto CONFIG_MISC_DEBUGMESSAGES_TOFILE   = "config_misc_debugMessages_toFile";
+       static constexpr auto CONFIG_MISC_TOOLTIPS               = "config_misc_tooltips";
+       static constexpr auto CONFIG_MISC_TOOLTIPS_DISABLED      = "config_misc_tooltips_disabled";
+       static constexpr auto CONFIG_MISC_TOOLTIPS_ENABLED       = "config_misc_tooltips_enabled";
+       static constexpr auto CONFIG_MISC_LANGUAGE               = "config_misc_language";
+       static constexpr auto CONFIG_MISC_NOLANGUAGESFOUND       = "config_misc_noLanguagesFound";
+
+       static constexpr auto CONFIG_PLUGINS_TITLE       = "config_plugins_title";
+       static constexpr auto CONFIG_PLUGINS_FOLDER      = "config_plugins_folder";
+       static constexpr auto CONFIG_PLUGINS_SCANNING    = "config_plugins_scanning";
+       static constexpr auto CONFIG_PLUGINS_SCAN        = "config_plugins_scan";
+       static constexpr auto CONFIG_PLUGINS_INVALIDPATH = "config_plugins_invalidPath";
+
+       LangMap();
+
+       const char* get(const std::string&) const;
+
+private:
+       Data        m_data;
+       std::string m_default;
+};
+
+/* -------------------------------------------------------------------------- */
+
+class LangMapper final : public Mapper
+{
+public:
+       LangMapper();
+
+       /* get
+       Gets a key from the currently loaded langmap file. */
+
+       const char* get(const std::string&) const;
+
+       /* init
+       Parses the langmap folders and find the available langmaps. */
+
+       void init();
+
+       /* read
+       Reads a langmap from file 'file' and sets it as the current one. */
+
+       int read(const std::string& file);
+
+private:
+       /* maps
+       The current langmap selected and loaded. It might be the default one (En_US) 
+    if no langmaps have been found. */
+
+       LangMap m_map;
+};
+} // namespace giada::v
+
+#endif
index 1b1e73248e2bf9b5cf0610c75ed5a7ea55417b30..02f845c103d0c078c1c9a0567a8d2e7b2b610f86 100644 (file)
@@ -96,6 +96,9 @@ void Ui::init(int argc, char** argv, m::Engine& engine)
        XInitThreads();
 #endif
 
+       langMapper.init();
+       langMapper.read(engine.conf.data.langMap);
+
        mainWindow = std::make_unique<gdMainWindow>(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT, "", argc, argv, engine.conf.data);
        mainWindow->resize(engine.conf.data.mainWindowX, engine.conf.data.mainWindowY, engine.conf.data.mainWindowW,
            engine.conf.data.mainWindowH);
index 116eaf05fa3cb7cf78904d4a0641cb1469622124..e47f90bb53bf32711548bb484a1ce14ba3d293f5 100644 (file)
@@ -31,6 +31,7 @@
 #include "core/patch.h"
 #include "gui/dialogs/mainWindow.h"
 #include "gui/dispatcher.h"
+#include "gui/langMapper.h"
 #include "gui/updater.h"
 #include <memory>
 #include <string>
@@ -123,6 +124,7 @@ public:
 
        std::unique_ptr<gdMainWindow> mainWindow;
        Dispatcher                    dispatcher;
+       LangMapper                    langMapper;
 
 private:
        static constexpr int BLINK_RATE = G_GUI_FPS / 2;
diff --git a/src/mapper.cpp b/src/mapper.cpp
new file mode 100644 (file)
index 0000000..adb232e
--- /dev/null
@@ -0,0 +1,73 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "mapper.h"
+#include "utils/fs.h"
+#include <filesystem>
+#include <fstream>
+
+namespace nl = nlohmann;
+
+namespace giada
+{
+void Mapper::init()
+{
+       if (!std::filesystem::exists(m_mapsPath))
+               return;
+
+       for (const auto& d : std::filesystem::directory_iterator(m_mapsPath))
+       {
+               if (!d.is_regular_file()) // TODO - better mechanism to check if it's a valid map
+                       continue;
+               m_mapFiles.push_back(d.path().filename().string());
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+std::optional<nlohmann::json> Mapper::read(const std::string& file) const
+{
+       if (file.empty())
+               return {};
+
+       std::ifstream ifs(u::fs::join(m_mapsPath, file));
+       if (!ifs.good())
+               return {};
+
+       nl::json j = nl::json::parse(ifs, nullptr, /*exceptions=*/false);
+       if (j.is_discarded())
+               return {};
+
+       return {j};
+}
+
+/* -------------------------------------------------------------------------- */
+
+const std::vector<std::string>& Mapper::getMapFilesFound() const
+{
+       return m_mapFiles;
+}
+} // namespace giada
diff --git a/src/mapper.h b/src/mapper.h
new file mode 100644 (file)
index 0000000..c22f13f
--- /dev/null
@@ -0,0 +1,69 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2022 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_MAPPER_H
+#define G_MAPPER_H
+
+#include <nlohmann/json.hpp>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace giada
+{
+class Mapper
+{
+public:
+       /* getMapFilesFound
+       Returns a reference to the list of maps found. */
+
+       const std::vector<std::string>& getMapFilesFound() const;
+
+       /* init
+       Parses the map folder m_mapsPath and find the available maps. */
+
+       void init();
+
+protected:
+       /* read
+       Reads a map from file 'file' as a JSON object. */
+
+       std::optional<nlohmann::json> read(const std::string& file) const;
+
+       /* m_mapsPath
+       Path to folder containing map files, different between OSes. */
+
+       std::string m_mapsPath;
+
+       /* m_mapFiles
+       The available map files. Each element of the vector represents a map file 
+    found in the map folder. */
+
+       std::vector<std::string> m_mapFiles;
+};
+} // namespace giada
+
+#endif
index 6f1979568657d5ed92a20644a891e08e4f9706df..eec222f28d91745dc9287bc39ac19d00d3f53fdf 100644 (file)
@@ -173,6 +173,20 @@ std::string getHomePath()
 
 /* -------------------------------------------------------------------------- */
 
+std::string getMidiMapsPath()
+{
+       auto out = stdfs::path(getHomePath()) / "midimaps";
+       return out.string();
+}
+
+std::string getLangMapsPath()
+{
+       auto out = stdfs::path(getHomePath()) / "langmaps";
+       return out.string();
+}
+
+/* -------------------------------------------------------------------------- */
+
 bool isRootDir(const std::string& s)
 {
        return stdfs::current_path().root_directory() == s;
@@ -192,4 +206,12 @@ std::string getUpDir(const std::string& s)
 
        return stdfs::path(s).parent_path().string();
 }
+
+/* -------------------------------------------------------------------------- */
+
+std::string join(const std::string& a, const std::string& b)
+{
+       auto out = stdfs::path(a) / stdfs::path(b);
+       return out.string();
+}
 } // namespace giada::u::fs
\ No newline at end of file
index b1f608e614981551c91acbc162eb20ab49d05dbc..1fb75238d6ab3a4c7275dad58e0da4749d17d83b 100644 (file)
@@ -46,6 +46,8 @@ bool        isProject(const std::string& s);
 bool        mkdir(const std::string& s);
 std::string getCurrentPath();
 std::string getHomePath();
+std::string getMidiMapsPath();
+std::string getLangMapsPath();
 
 /* getRealPath
 Expands all symbolic links and resolves references to /./, /../ and extra / 
@@ -80,6 +82,11 @@ Returns the upper directory:
 /path/to/my/directory -> /path/to/my/ */
 
 std::string getUpDir(const std::string& s);
+
+/* join
+Joins two string paths using the correct separator. */
+
+std::string join(const std::string& a, const std::string& b);
 } // namespace giada::u::fs
 
 #endif
index 42a1d0f132e3d9fcdb1ee0aabef09b52d6c5d17b..c22336911e8dd14239385e5473c5f997ebc0c7c4 100644 (file)
@@ -38,7 +38,7 @@ int init(int m)
        stat = true;
        if (mode == LOG_MODE_FILE)
        {
-               std::string fpath = fs::getHomePath() + G_SLASH + "giada.log";
+               std::string fpath = u::fs::join(fs::getHomePath(), "giada.log");
                f                 = std::fopen(fpath.c_str(), "a");
                if (!f)
                {
diff --git a/vcpkg.json b/vcpkg.json
new file mode 100644 (file)
index 0000000..e9a4c34
--- /dev/null
@@ -0,0 +1,34 @@
+{
+    "name": "giada",
+    "version-string": "1.0",
+    "builtin-baseline": "af2287382b1991dbdcb7e5112d236f3323b9dd7a",
+    "dependencies": [
+        {
+            "name": "rtmidi",
+            "version>=": "5.0.0"
+        },
+        {
+            "name": "fmt",
+            "version>=": "8.1.1"
+        },
+        {
+            "name": "fltk",
+            "version>=": "1.3.8"
+        },
+        {
+            "name": "catch2",
+            "version>=": "2.13.8"
+        },
+        {
+            "name": "libsamplerate",
+            "version>=": "0.2.2"
+        },
+        {
+            "name": "libsndfile",
+            "version>=": "1.0.31",
+            "features": [
+                "external-libs"
+            ]
+        }
+    ]
+}
\ No newline at end of file