diff --git a/.clang-format b/.clang-format index 6be42bc1..0e46a99b 100644 --- a/.clang-format +++ b/.clang-format @@ -12,7 +12,7 @@ AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: Never AllowShortLambdasOnASingleLine: All -AllowShortLoopsOnASingleLine: true +AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakTemplateDeclarations: MultiLine BinPackArguments: false diff --git a/docs/changelog.md b/docs/changelog.md index 9b369914..4ba66cb4 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -9,6 +9,7 @@ + Added sublayer support for outbound messages + Enabled slider mappings for virtual devices + Renamed velocity to data_2 to be more aligned with the midi specification ++ Added paging to logging windows for better performance, remove max log setting ----------------------------------------------------------------------------------------------------------------------- diff --git a/src/common/midi_logger.cpp b/src/common/midi_logger.cpp index 8c347996..c8bee77d 100644 --- a/src/common/midi_logger.cpp +++ b/src/common/midi_logger.cpp @@ -29,9 +29,8 @@ namespace xmidictrl { /** * Constructor */ -midi_logger::midi_logger(bool in_enabled, int in_max_messages) +midi_logger::midi_logger(bool in_enabled) : m_enabled(in_enabled) - , m_max_messages(in_max_messages) {} @@ -89,26 +88,10 @@ void midi_logger::disable() } -/** - * Set the maximum number of midi messages in the logger - * - * @param in_max_messages max. number of messages - */ -void midi_logger::set_max_messages(int in_max_messages) -{ - std::mutex mutex; - std::scoped_lock lock(mutex); - - m_max_messages = in_max_messages; - - adjust_log_size(); -} - - /** * Return a specific midi message */ -midi_message* midi_logger::message(int in_index) +midi_message* midi_logger::message(size_t in_index) { std::mutex mutex; std::scoped_lock lock(mutex); @@ -128,21 +111,7 @@ void midi_logger::add(const std::shared_ptr& in_msg) if (!m_enabled) return; - adjust_log_size(); - m_messages.push_back(in_msg); } - -/** - * Adjust the log size depending on the current settings - */ -void midi_logger::adjust_log_size() -{ - std::mutex mutex; - std::lock_guard lock(mutex); - - while (m_messages.size() >= m_max_messages) m_messages.pop_front(); -} - } // Namespace xmidictrl diff --git a/src/common/midi_logger.h b/src/common/midi_logger.h index 00755fb4..88e4484a 100644 --- a/src/common/midi_logger.h +++ b/src/common/midi_logger.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------- // XMidiCtrl - MIDI Controller plugin for X-Plane // -// Copyright (c) 2021-2023 Marco Auer +// Copyright (c) 2021-2024 Marco Auer // // XMidiCtrl is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -29,28 +29,23 @@ namespace xmidictrl { class midi_logger { public: - explicit midi_logger(bool in_enabled, int in_max_messages); - ~midi_logger() = default; + explicit midi_logger(bool in_enabled); + ~midi_logger() = default; - void clear(); - size_t count(); + void clear(); + size_t count(); - void enable(); - void disable(); + void enable(); + void disable(); - void set_max_messages(int in_max_messages); + midi_message* message(size_t in_index); - midi_message* message(int in_index); - - void add(const std::shared_ptr& in_msg); + void add(const std::shared_ptr& in_msg); private: - void adjust_log_size(); - - bool m_enabled; - int m_max_messages; + bool m_enabled; - std::deque> m_messages; + std::deque> m_messages; }; } // Namespace xmidictrl diff --git a/src/common/text_logger.cpp b/src/common/text_logger.cpp index 8431ea7e..6e655155 100644 --- a/src/common/text_logger.cpp +++ b/src/common/text_logger.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------- // XMidiCtrl - MIDI Controller plugin for X-Plane // -// Copyright (c) 2021-2023 Marco Auer +// Copyright (c) 2021-2024 Marco Auer // // XMidiCtrl is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -37,10 +37,10 @@ namespace xmidictrl { * Constructor */ text_logger::text_logger(text_logger* in_parent) - : m_parent(in_parent) + : m_parent(in_parent) { - if (in_parent != nullptr) - set_debug_mode(in_parent->debug_mode()); + if (in_parent != nullptr) + set_debug_mode(in_parent->debug_mode()); } @@ -55,15 +55,15 @@ text_logger::text_logger(text_logger* in_parent) */ void text_logger::enable_file_logging(const std::filesystem::path& in_path) { - if (!in_path.empty()) { - std::string filename = in_path.string() + XMIDICTRL_NAME + LOGFILE_SUFFIX; - - m_file_stream.open(filename, std::ios_base::out | std::ios_base::trunc); - if (!m_file_stream.is_open()) - error(fmt::format("Failed to open log file '{}'", filename)); - } else { - error("Cannot open log file as the give file path is empty"); - } + if (!in_path.empty()) { + std::string filename = in_path.string() + XMIDICTRL_NAME + LOGFILE_SUFFIX; + + m_file_stream.open(filename, std::ios_base::out | std::ios_base::trunc); + if (!m_file_stream.is_open()) + error(fmt::format("Failed to open log file '{}'", filename)); + } else { + error("Cannot open log file as the give file path is empty"); + } } @@ -72,7 +72,7 @@ void text_logger::enable_file_logging(const std::filesystem::path& in_path) */ void text_logger::set_debug_mode(bool in_mode) { - m_debug_mode = in_mode; + m_debug_mode = in_mode; } @@ -81,7 +81,7 @@ void text_logger::set_debug_mode(bool in_mode) */ bool text_logger::debug_mode() const { - return m_debug_mode; + return m_debug_mode; } @@ -90,22 +90,7 @@ bool text_logger::debug_mode() const */ void text_logger::set_log_info(bool in_mode) { - m_log_info = in_mode; -} - - -/** - * Set the max message size - */ -void text_logger::set_max_size(int in_size) -{ - std::mutex mutex; - std::lock_guard lock(mutex); - - m_max_size = in_size; - - while (m_messages.size() > m_max_size) - m_messages.pop_front(); + m_log_info = in_mode; } @@ -114,13 +99,13 @@ void text_logger::set_max_size(int in_size) */ void text_logger::clear() { - std::mutex mutex; - std::lock_guard lock(mutex); + std::mutex mutex; + std::lock_guard lock(mutex); - m_error_count = 0; - m_warn_count = 0; + m_error_count = 0; + m_warn_count = 0; - m_messages.clear(); + m_messages.clear(); } @@ -129,22 +114,22 @@ void text_logger::clear() */ size_t text_logger::count() { - std::mutex mutex; - std::lock_guard lock(mutex); + std::mutex mutex; + std::lock_guard lock(mutex); - return m_messages.size(); + return m_messages.size(); } /** * Return a specific text message */ -text_log_msg* text_logger::message(int in_index) +text_log_msg* text_logger::message(size_t in_index) { - std::mutex mutex; - std::lock_guard lock(mutex); + std::mutex mutex; + std::lock_guard lock(mutex); - return m_messages.at(in_index).get(); + return m_messages.at(in_index).get(); } @@ -153,23 +138,23 @@ text_log_msg* text_logger::message(int in_index) */ std::string text_logger::messages_as_text() { - std::mutex mutex; - std::lock_guard lock(mutex); - - if (m_messages.size() == 1) - return {m_messages.at(0)->text}; - - std::string text; - for (auto& msg: m_messages) { - if (text.empty()) { - text = msg->text; - } else { - text.append("\n"); - text.append(msg->text); - } - } - - return text; + std::mutex mutex; + std::lock_guard lock(mutex); + + if (m_messages.size() == 1) + return {m_messages.at(0)->text}; + + std::string text; + for (auto& msg: m_messages) { + if (text.empty()) { + text = msg->text; + } else { + text.append("\n"); + text.append(msg->text); + } + } + + return text; } @@ -178,10 +163,10 @@ std::string text_logger::messages_as_text() */ bool text_logger::has_errors() const { - std::mutex mutex; - std::lock_guard lock(mutex); + std::mutex mutex; + std::lock_guard lock(mutex); - return (m_error_count > 0); + return (m_error_count > 0); } @@ -190,10 +175,10 @@ bool text_logger::has_errors() const */ bool text_logger::has_warnings() const { - std::mutex mutex; - std::lock_guard lock(mutex); + std::mutex mutex; + std::lock_guard lock(mutex); - return (m_warn_count > 0); + return (m_warn_count > 0); } @@ -202,10 +187,10 @@ bool text_logger::has_warnings() const */ void text_logger::debug(std::string_view in_text) { - create_message(log_level::debug, in_text); + create_message(log_level::debug, in_text); - if (m_parent != nullptr) - m_parent->create_message(log_level::debug, in_text); + if (m_parent != nullptr) + m_parent->create_message(log_level::debug, in_text); } @@ -214,7 +199,7 @@ void text_logger::debug(std::string_view in_text) */ void text_logger::debug_line(std::uint_least32_t in_line, std::string_view in_text) { - debug(fmt::format(" --> Line {} :: {}", in_line, utils::trim(in_text))); + debug(fmt::format(" --> Line {} :: {}", in_line, utils::trim(in_text))); } @@ -223,7 +208,7 @@ void text_logger::debug_line(std::uint_least32_t in_line, std::string_view in_te */ void text_logger::debug_param(std::uint_least32_t in_line, std::string_view in_param, std::string_view in_value) { - debug_line(in_line, fmt::format("Parameter '{}' = '{}'", in_param, in_value)); + debug_line(in_line, fmt::format("Parameter '{}' = '{}'", in_param, in_value)); } @@ -232,10 +217,10 @@ void text_logger::debug_param(std::uint_least32_t in_line, std::string_view in_p */ void text_logger::info(std::string_view in_text) { - create_message(log_level::info, in_text); + create_message(log_level::info, in_text); - if (m_parent != nullptr) - m_parent->create_message(log_level::info, in_text); + if (m_parent != nullptr) + m_parent->create_message(log_level::info, in_text); } @@ -244,10 +229,10 @@ void text_logger::info(std::string_view in_text) */ void text_logger::warn(std::string_view in_text) { - create_message(log_level::warn, in_text); + create_message(log_level::warn, in_text); - if (m_parent != nullptr) - m_parent->create_message(log_level::warn, in_text); + if (m_parent != nullptr) + m_parent->create_message(log_level::warn, in_text); } @@ -256,7 +241,7 @@ void text_logger::warn(std::string_view in_text) */ void text_logger::warn_line(std::uint_least32_t in_line, std::string_view in_text) { - warn(fmt::format(" --> Line {} :: {}", in_line, utils::trim(in_text))); + warn(fmt::format(" --> Line {} :: {}", in_line, utils::trim(in_text))); } @@ -265,10 +250,10 @@ void text_logger::warn_line(std::uint_least32_t in_line, std::string_view in_tex */ void text_logger::error(std::string_view in_text) { - create_message(log_level::error, in_text); + create_message(log_level::error, in_text); - if (m_parent != nullptr) - m_parent->create_message(log_level::error, in_text); + if (m_parent != nullptr) + m_parent->create_message(log_level::error, in_text); } @@ -277,12 +262,12 @@ void text_logger::error(std::string_view in_text) */ void text_logger::error_line(std::uint_least32_t in_line, std::string_view in_text) { - std::string debug_text = fmt::format(" --> Line {} :: {}", in_line, utils::trim(in_text)); + std::string debug_text = fmt::format(" --> Line {} :: {}", in_line, utils::trim(in_text)); - create_message(log_level::error, debug_text); + create_message(log_level::error, debug_text); - if (m_parent != nullptr) - m_parent->create_message(log_level::error, debug_text); + if (m_parent != nullptr) + m_parent->create_message(log_level::error, debug_text); } @@ -297,23 +282,23 @@ void text_logger::error_line(std::uint_least32_t in_line, std::string_view in_te */ bool text_logger::check_log_level(const log_level in_level) const { - switch (in_level) { - case log_level::error: - case log_level::warn: - return true; - - case log_level::info: - if (m_log_info || m_debug_mode) - return true; - break; - - case log_level::debug: - if (m_debug_mode) - return true; - break; - } - - return false; + switch (in_level) { + case log_level::error: + case log_level::warn: + return true; + + case log_level::info: + if (m_log_info || m_debug_mode) + return true; + break; + + case log_level::debug: + if (m_debug_mode) + return true; + break; + } + + return false; } @@ -322,9 +307,9 @@ bool text_logger::check_log_level(const log_level in_level) const */ void text_logger::create_message(log_level in_level, std::string_view in_text) { - if (check_log_level(in_level)) - // add message to internal list and write to file stream - add_message(in_level, in_text); + if (check_log_level(in_level)) + // add message to internal list and write to file stream + add_message(in_level, in_text); } @@ -333,68 +318,63 @@ void text_logger::create_message(log_level in_level, std::string_view in_text) */ void text_logger::add_message(log_level in_level, std::string_view in_text) { - std::mutex mutex; - std::lock_guard lock(mutex); + std::mutex mutex; + std::lock_guard lock(mutex); - if (in_level == log_level::warn) - m_warn_count++; + if (in_level == log_level::warn) + m_warn_count++; - if (in_level == log_level::error) - m_error_count++; + if (in_level == log_level::error) + m_error_count++; - // get current date time stamp - time_t t = std::time(nullptr); + // get current date time stamp + time_t t = std::time(nullptr); #ifdef _MSC_VER - std::tm time_info {}; - localtime_s(&time_info, &t); + std::tm time_info {}; + localtime_s(&time_info, &t); #else - std::tm time_info = *std::localtime(&t); - //struct std::tm* time_info = localtime(&t); + std::tm time_info = *std::localtime(&t); + //struct std::tm* time_info = localtime(&t); #endif - // format into a string - char datetime_str[32]; - std::strftime(&datetime_str[0], sizeof(datetime_str), "%Y-%m-%d %H:%M:%S", &time_info); - - // add message to internal list - std::shared_ptr msg = std::make_shared(); - msg->time = datetime_str; - msg->level = in_level; - msg->text = in_text; + // format into a string + char datetime_str[32]; + std::strftime(&datetime_str[0], sizeof(datetime_str), "%Y-%m-%d %H:%M:%S", &time_info); - if (m_debug_mode) { - while (m_messages.size() >= m_max_size) - m_messages.pop_front(); - } + // add message to internal list + std::shared_ptr msg = std::make_shared(); + msg->time = datetime_str; + msg->level = in_level; + msg->text = in_text; - m_messages.push_back(msg); + m_messages.push_back(msg); - // write message to file stream - if (m_file_stream.is_open()) { - m_file_stream << msg->time; + // write message to file stream + if (m_file_stream.is_open()) { + m_file_stream << msg->time; - switch (msg->level) { - case log_level::error: - m_file_stream << " [ERROR] "; - break; + switch (msg->level) { + case log_level::error: + m_file_stream << " [ERROR] "; + break; - case log_level::warn: - m_file_stream << " [WARN] "; - break; + case log_level::warn: + m_file_stream << " [WARN] "; + break; - case log_level::info: - m_file_stream << " [INFO] "; - break; + case log_level::info: + m_file_stream << " [INFO] "; + break; - case log_level::debug: - m_file_stream << " [DEBUG] "; - break; - } + case log_level::debug: + m_file_stream << " [DEBUG] "; + break; + } - m_file_stream << msg->text; - m_file_stream << std::endl; - } + m_file_stream << msg->text; + m_file_stream << std::endl; + } } } // Namespace xmidictrl \ No newline at end of file diff --git a/src/common/text_logger.h b/src/common/text_logger.h index d239be81..5daf67d2 100644 --- a/src/common/text_logger.h +++ b/src/common/text_logger.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------- // XMidiCtrl - MIDI Controller plugin for X-Plane // -// Copyright (c) 2021-2023 Marco Auer +// Copyright (c) 2021-2024 Marco Auer // // XMidiCtrl is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -35,56 +35,54 @@ namespace xmidictrl { class text_logger { public: - explicit text_logger(text_logger* in_parent = nullptr); - ~text_logger() = default; + explicit text_logger(text_logger* in_parent = nullptr); + ~text_logger() = default; - void enable_file_logging(const std::filesystem::path& in_path); + void enable_file_logging(const std::filesystem::path& in_path); - void set_debug_mode(bool in_mode); - [[nodiscard]] bool debug_mode() const; + void set_debug_mode(bool in_mode); + [[nodiscard]] bool debug_mode() const; - void set_log_info(bool in_mode); - void set_max_size(int in_size); + void set_log_info(bool in_mode); - void clear(); - size_t count(); - text_log_msg* message(int in_index); + void clear(); + size_t count(); + text_log_msg* message(size_t in_index); - std::string messages_as_text(); + std::string messages_as_text(); - [[nodiscard]] bool has_errors() const; - [[nodiscard]] bool has_warnings() const; + [[nodiscard]] bool has_errors() const; + [[nodiscard]] bool has_warnings() const; - void debug(std::string_view in_text); - void debug_line(std::uint_least32_t in_line, std::string_view in_text); - void debug_param(std::uint_least32_t in_line, std::string_view in_param, std::string_view in_value); + void debug(std::string_view in_text); + void debug_line(std::uint_least32_t in_line, std::string_view in_text); + void debug_param(std::uint_least32_t in_line, std::string_view in_param, std::string_view in_value); - void info(std::string_view in_text); + void info(std::string_view in_text); - void warn(std::string_view in_text); - void warn_line(std::uint_least32_t in_line, std::string_view in_text); + void warn(std::string_view in_text); + void warn_line(std::uint_least32_t in_line, std::string_view in_text); - void error(std::string_view in_text); - void error_line(std::uint_least32_t in_line, std::string_view in_text); + void error(std::string_view in_text); + void error_line(std::uint_least32_t in_line, std::string_view in_text); private: - [[nodiscard]] bool check_log_level(log_level in_level) const; + [[nodiscard]] bool check_log_level(log_level in_level) const; - void create_message(log_level in_level, std::string_view in_text); - void add_message(log_level in_level, std::string_view in_text); + void create_message(log_level in_level, std::string_view in_text); + void add_message(log_level in_level, std::string_view in_text); - text_logger* m_parent; + text_logger* m_parent; - int m_error_count {0}; - int m_warn_count {0}; - int m_max_size {1000}; + int m_error_count {0}; + int m_warn_count {0}; - bool m_debug_mode {false}; - bool m_log_info {true}; + bool m_debug_mode {false}; + bool m_log_info {true}; - std::ofstream m_file_stream; + std::ofstream m_file_stream; - std::deque> m_messages; + std::deque> m_messages; }; } // Namespace xmidictrl diff --git a/src/common/types.h b/src/common/types.h index 38dbf8ee..6a910ea8 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------- // XMidiCtrl - MIDI Controller plugin for X-Plane // -// Copyright (c) 2021-2023 Marco Auer +// Copyright (c) 2021-2024 Marco Auer // // XMidiCtrl is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -96,8 +96,6 @@ const char* const CFG_KEY_LOG_MIDI = "log_midi"; const char* const CFG_KEY_MAPPING_IN = "mapping_in"; const char* const CFG_KEY_MAPPING_INIT = "mapping_init"; const char* const CFG_KEY_MAPPING_OUT = "mapping_out"; -const char* const CFG_KEY_MAX_MIDI_MESSAGES = "max_midi_messages"; -const char* const CFG_KEY_MAX_TEXT_MESSAGES = "max_text_messages"; const char* const CFG_KEY_MODE = "mode"; const char* const CFG_KEY_MODE_NOTE = "mode_note"; const char* const CFG_KEY_MODE_OUT = "mode_out"; diff --git a/src/env/settings.cpp b/src/env/settings.cpp index 6fec9d39..d44a2001 100644 --- a/src/env/settings.cpp +++ b/src/env/settings.cpp @@ -41,9 +41,6 @@ settings::settings(text_logger& in_text_log, std::filesystem::path in_path) m_virtual_channel = toml::find_or(m_settings_file, CFG_KEY_VIRTUAL_CHANNEL, 16); m_default_outbound_delay = toml::find_or(m_settings_file, CFG_KEY_DEFAULT_OUTBOUND_DELAY, 0.5f); - m_max_text_messages = toml::find_or(m_settings_file, CFG_KEY_MAX_TEXT_MESSAGES, 1500); - m_max_midi_messages = toml::find_or(m_settings_file, CFG_KEY_MAX_MIDI_MESSAGES, 150); - m_note_name = static_cast(toml::find_or(m_settings_file, CFG_KEY_NOTE_NAME, 0)); m_default_text_sort = static_cast(toml::find_or(m_settings_file, CFG_KEY_DEFAULT_TEXT_SORT, 0)); @@ -159,43 +156,6 @@ float settings::default_outbound_delay() const } -/** - * Sets the max number of text messages to be logged - */ -void settings::set_max_text_messages(int in_number) -{ - m_max_text_messages = in_number; - m_text_log.set_max_size(in_number); -} - - -/** - * Return the max number of text messages to be logged - */ -int settings::max_text_messages() const -{ - return m_max_text_messages; -} - - -/** - * Sets the max number of midi messages to be logged - */ -void settings::set_max_midi_messages(int in_number) -{ - m_max_midi_messages = in_number; -} - - -/** - * Return the max number of midi messages to be logged - */ -int settings::max_midi_messages() const -{ - return m_max_midi_messages; -} - - /** * Set the default sort mode for text messages */ @@ -367,9 +327,6 @@ void settings::save_settings() m_settings_file[CFG_KEY_LOG_MIDI] = m_log_midi; m_settings_file[CFG_KEY_SHOW_ERRORS] = m_show_errors; - m_settings_file[CFG_KEY_MAX_TEXT_MESSAGES] = m_max_text_messages; - m_settings_file[CFG_KEY_MAX_MIDI_MESSAGES] = m_max_midi_messages; - m_settings_file[CFG_KEY_NOTE_NAME] = static_cast(m_note_name); m_settings_file[CFG_KEY_DEFAULT_TEXT_SORT] = static_cast(m_default_text_sort); diff --git a/src/env/settings.h b/src/env/settings.h index 6541b21d..ba66b3f9 100644 --- a/src/env/settings.h +++ b/src/env/settings.h @@ -33,90 +33,81 @@ namespace xmidictrl { class settings { public: - explicit settings(text_logger& in_text_log, std::filesystem::path in_path); - ~settings() = default; + explicit settings(text_logger& in_text_log, std::filesystem::path in_path); + ~settings() = default; - void set_debug_mode(bool in_enabled); - [[nodiscard]] bool debug_mode() const; + void set_debug_mode(bool in_enabled); + [[nodiscard]] bool debug_mode() const; - void set_log_midi(bool in_enabled); - [[nodiscard]] bool log_midi() const; + void set_log_midi(bool in_enabled); + [[nodiscard]] bool log_midi() const; - void set_show_errors(bool in_enabled); - [[nodiscard]] bool show_errors() const; + void set_show_errors(bool in_enabled); + [[nodiscard]] bool show_errors() const; - void set_virtual_channel(int in_channel); - [[nodiscard]] int virtual_channel() const; + void set_virtual_channel(int in_channel); + [[nodiscard]] int virtual_channel() const; - void set_default_outbound_delay(float in_delay); - [[nodiscard]] float default_outbound_delay() const; + void set_default_outbound_delay(float in_delay); + [[nodiscard]] float default_outbound_delay() const; - void set_max_text_messages(int in_number); - [[nodiscard]] int max_text_messages() const; + void set_default_text_sort(sort_mode in_mode); + [[nodiscard]] sort_mode default_text_sort() const; - void set_max_midi_messages(int in_number); - [[nodiscard]] int max_midi_messages() const; + void set_default_midi_sort(sort_mode in_mode); + [[nodiscard]] sort_mode default_midi_sort() const; - void set_default_text_sort(sort_mode in_mode); - [[nodiscard]] sort_mode default_text_sort() const; + void set_note_name(note_name_type in_type); + [[nodiscard]] note_name_type note_name() const; - void set_default_midi_sort(sort_mode in_mode); - [[nodiscard]] sort_mode default_midi_sort() const; + void set_use_common_profile(bool in_enabled); + [[nodiscard]] bool use_common_profile() const; - void set_note_name(note_name_type in_type); - [[nodiscard]] note_name_type note_name() const; + void set_info_disabled(bool in_disabled); + [[nodiscard]] bool info_disabled() const; - void set_use_common_profile(bool in_enabled); - [[nodiscard]] bool use_common_profile() const; + void set_info_position(window_position in_position); + [[nodiscard]] window_position info_position() const; - void set_info_disabled(bool in_disabled); - [[nodiscard]] bool info_disabled() const; + void set_info_offset_x(int in_offset); + [[nodiscard]] int info_offset_x() const; - void set_info_position(window_position in_position); - [[nodiscard]] window_position info_position() const; + void set_info_offset_y(int in_offset); + [[nodiscard]] int info_offset_y() const; - void set_info_offset_x(int in_offset); - [[nodiscard]] int info_offset_x() const; + void set_info_seconds(int in_seconds); + [[nodiscard]] int info_seconds() const; - void set_info_offset_y(int in_offset); - [[nodiscard]] int info_offset_y() const; - - void set_info_seconds(int in_seconds); - [[nodiscard]] int info_seconds() const; - - void save_settings(); + void save_settings(); private: - std::string get_settings_filename(); - - text_logger& m_text_log; + std::string get_settings_filename(); - std::filesystem::path m_settings_path {}; - toml::value m_settings_file {}; + text_logger& m_text_log; - bool m_debug_mode {false}; - bool m_log_midi {true}; - bool m_show_errors {true}; + std::filesystem::path m_settings_path {}; + toml::value m_settings_file {}; - int m_virtual_channel {16}; - float m_default_outbound_delay {0.5f}; + bool m_debug_mode {false}; + bool m_log_midi {true}; + bool m_show_errors {true}; - int m_max_text_messages {1500}; - int m_max_midi_messages {150}; + int m_virtual_channel {16}; + float m_default_outbound_delay {0.5f}; - note_name_type m_note_name {note_name_type::sharp}; + note_name_type m_note_name {note_name_type::sharp}; - sort_mode m_default_text_sort {sort_mode::ascending}; - sort_mode m_default_midi_sort {sort_mode::ascending}; + sort_mode m_default_text_sort {sort_mode::ascending}; + sort_mode m_default_midi_sort {sort_mode::ascending}; - bool m_use_common_profile {true}; + bool m_use_common_profile {true}; - bool m_info_disabled {false}; + bool m_info_disabled {false}; - window_position m_info_position {window_position::bottom_left}; - int m_info_offset_x {50}; - int m_info_offset_y {50}; - int m_info_seconds {3}; + window_position m_info_position {window_position::bottom_left}; + int m_info_offset_x {50}; + int m_info_offset_y {50}; + int m_info_seconds {3}; }; } // Namespace xmidictrl diff --git a/src/plugin/plugin.cpp b/src/plugin/plugin.cpp index 499c234e..015623c6 100644 --- a/src/plugin/plugin.cpp +++ b/src/plugin/plugin.cpp @@ -53,7 +53,6 @@ plugin::plugin() if (m_env->create_preference_folders(*m_plugin_log)) { m_plugin_log->enable_file_logging(m_env->preferences_path()); m_plugin_log->set_debug_mode(m_env->settings().debug_mode()); - m_plugin_log->set_max_size(m_env->settings().max_text_messages()); } else { m_plugin_log->info("Cannot create preference folder for " XMIDICTRL_FULL_NAME); XPLMDebugString(std::string_view("Cannot create preference folder for " XMIDICTRL_FULL_NAME).data()); @@ -66,7 +65,7 @@ plugin::plugin() m_menu = std::make_unique(); // create the midi log - m_midi_log = std::make_unique(m_env->settings().log_midi(), m_env->settings().max_midi_messages()); + m_midi_log = std::make_unique(m_env->settings().log_midi()); // create the aircraft profile m_profile = std::make_unique(*m_plugin_log, *m_midi_log, *m_env); diff --git a/src/plugin/ui/log_viewer.cpp b/src/plugin/ui/log_viewer.cpp index cb0bf510..e5ff46e0 100644 --- a/src/plugin/ui/log_viewer.cpp +++ b/src/plugin/ui/log_viewer.cpp @@ -20,6 +20,9 @@ // Font Awesome #include +// fmt +#include "fmt/format.h" + // XMidiCtrl #include "plugin.h" #include "types.h" @@ -33,7 +36,8 @@ namespace xmidictrl { /** * Constructor */ -log_viewer::log_viewer(text_logger& in_text_log, environment& in_env) : imgui_window(in_text_log, in_env, 1400, 700) +log_viewer::log_viewer(text_logger& in_text_log, environment& in_env) + : imgui_window(in_text_log, in_env, 1400, 700) { set_title(std::string(XMIDICTRL_NAME) + " - Log Viewer"); @@ -58,7 +62,8 @@ void log_viewer::create_widgets() { ImGui::Text("Debug Mode:"); ImGui::SameLine(150); - if (log().debug_mode()) + + if (env().settings().log_midi()) ImGui::TextColored(value_color(), "Enabled (%i)", static_cast(log().count())); else ImGui::TextColored(value_color(), "Disabled"); @@ -74,15 +79,53 @@ void log_viewer::create_widgets() log().clear(); ImGui::NewLine(); - ImGui::TextColored(title_color(), "%s", "MESSAGES"); + ImGui::TextColored(title_color(), "MESSAGES"); + + ImGui::SameLine(150); + + if (ImGui::Button(UI_SPACER_2 ICON_FA_ARROW_LEFT UI_SPACER_2)) { + if (m_page > 0) + m_page--; + } + + ImGui::SameLine(); + + size_t start = 0; + size_t end = 0; + + if (m_log_sort_mode == sort_mode::ascending) { + start = m_page * c_no_msg_page; + end = (m_page + 1) * c_no_msg_page; + + if (end > log().count()) + end = log().count(); + } else if (log().count() > 0) { + start = (m_page + 1) * c_no_msg_page; + end = m_page * c_no_msg_page; + + if (start > log().count() - 1) + start = log().count() - 1; + } + + size_t no_pages = (log().count() + c_no_msg_page - 1) / c_no_msg_page; + ImGui::Text("%s", fmt::format("{} / {}", m_page + 1, no_pages).c_str()); + + ImGui::SameLine(); + + if (ImGui::Button(UI_SPACER_2 ICON_FA_ARROW_RIGHT UI_SPACER_2)) { + if ((m_page + 1) * c_no_msg_page < log().count()) + m_page++; + } + ImGui::Separator(); ImGui::BeginChild("LOG_TABLE"); if (ImGui::BeginTable("tableLogMessages", - 3, + 4, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_ScrollY)) { + ImGui::TableSetupColumn("No", ImGuiTableColumnFlags_WidthFixed, 25); ImGui::TableSetupColumn("Date/Time", m_log_msg_flags, 200); ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 120); ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthStretch); @@ -93,7 +136,7 @@ void log_viewer::create_widgets() if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs()) { if (sort_specs->SpecsDirty && sort_specs->SpecsCount > 0) { auto spec = sort_specs->Specs[0]; - if (spec.ColumnIndex == 0 && spec.SortDirection == ImGuiSortDirection_Ascending) + if (spec.ColumnIndex == 1 && spec.SortDirection == ImGuiSortDirection_Ascending) m_log_sort_mode = sort_mode::ascending; else m_log_sort_mode = sort_mode::descending; @@ -101,15 +144,9 @@ void log_viewer::create_widgets() } if (m_log_sort_mode == sort_mode::ascending) { - for (size_t i = 0; i < log().count(); i++) { - auto msg = log().message(static_cast(i)); - add_log_row(msg); - } + for (size_t i = start; i < end; i++) add_log_row(i, log().message(i)); } else if (log().count() > 0) { - for (size_t i = log().count() - 1; i > 0; i--) { - auto msg = log().message(static_cast(i)); - add_log_row(msg); - } + for (size_t i = start; i > end; i--) add_log_row(i, log().message(i)); } } ImGui::EndTable(); @@ -126,10 +163,13 @@ void log_viewer::create_widgets() /** * Add a log message to the table */ -void log_viewer::add_log_row(text_log_msg* in_msg) +void log_viewer::add_log_row(size_t in_no, text_log_msg* in_msg) { ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(fmt::format("{}", in_no).c_str()); + ImGui::TableNextColumn(); ImGui::TextUnformatted(in_msg->time.c_str()); diff --git a/src/plugin/ui/log_viewer.h b/src/plugin/ui/log_viewer.h index 12a9b661..91ab563a 100644 --- a/src/plugin/ui/log_viewer.h +++ b/src/plugin/ui/log_viewer.h @@ -40,11 +40,16 @@ class log_viewer : public imgui_window { void create_widgets() override; private: - void add_log_row(text_log_msg* in_msg); + // constants + static constexpr unsigned int c_no_msg_page {500}; + // members sort_mode m_log_sort_mode {sort_mode::ascending}; + unsigned int m_page {0}; ImGuiTableColumnFlags m_log_msg_flags; + + void add_log_row(size_t in_no, text_log_msg* in_msg); }; } // Namespace xmidictrl diff --git a/src/plugin/ui/midi_watcher.cpp b/src/plugin/ui/midi_watcher.cpp index d92f60bb..6e5f27fb 100644 --- a/src/plugin/ui/midi_watcher.cpp +++ b/src/plugin/ui/midi_watcher.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------- // XMidiCtrl - MIDI Controller plugin for X-Plane // -// Copyright (c) 2021-2023 Marco Auer +// Copyright (c) 2021-2024 Marco Auer // // XMidiCtrl is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -20,6 +20,9 @@ // Font Awesome #include +// fmt +#include "fmt/format.h" + // XMidiCtrl #include "midi_message.h" #include "plugin.h" @@ -34,7 +37,8 @@ namespace xmidictrl { * Constructor */ midi_watcher::midi_watcher(text_logger& in_text_log, midi_logger& in_midi_log, environment& in_env) - : imgui_window(in_text_log, in_env, 1400, 700), m_midi_log(in_midi_log) + : imgui_window(in_text_log, in_env, 1400, 700) + , m_midi_log(in_midi_log) { set_title(std::string(XMIDICTRL_NAME) + " - MIDI Watcher"); @@ -77,9 +81,46 @@ void midi_watcher::create_widgets() ImGui::NewLine(); ImGui::TextColored(title_color(), "%s", "MESSAGES"); + + ImGui::SameLine(150); + + if (ImGui::Button(UI_SPACER_2 ICON_FA_ARROW_LEFT UI_SPACER_2)) { + if (m_page > 0) + m_page--; + } + + ImGui::SameLine(); + + size_t start = 0; + size_t end = 0; + + if (m_midi_sort_mode == sort_mode::ascending) { + start = m_page * c_no_msg_page; + end = (m_page + 1) * c_no_msg_page; + + if (end > m_midi_log.count()) + end = m_midi_log.count(); + } else if (m_midi_log.count() > 0) { + start = (m_page + 1) * c_no_msg_page; + end = m_page * c_no_msg_page; + + if (start > m_midi_log.count() - 1) + start = m_midi_log.count() - 1; + } + + size_t no_pages = (m_midi_log.count() + c_no_msg_page - 1) / c_no_msg_page; + ImGui::Text("%s", fmt::format("{} / {}", m_page + 1, no_pages).c_str()); + + ImGui::SameLine(); + + if (ImGui::Button(UI_SPACER_2 ICON_FA_ARROW_RIGHT UI_SPACER_2)) { + if ((m_page + 1) * c_no_msg_page < m_midi_log.count()) + m_page++; + } + ImGui::Separator(); - ImGui::BeginChild("TEXT_TABLE"); + ImGui::BeginChild("MIDI_LOG_TABLE"); if (ImGui::BeginTable("tableMidiMessages", 10, @@ -110,15 +151,11 @@ void midi_watcher::create_widgets() } if (m_midi_sort_mode == sort_mode::ascending) { - for (size_t i = 0; i < m_midi_log.count(); i++) { - auto msg = m_midi_log.message(static_cast(i)); - add_midi_row(msg); - } + for (size_t i = start; i < end; i++) + add_midi_row(m_midi_log.message(i)); } else if (m_midi_log.count() > 0) { - for (size_t i = m_midi_log.count() - 1; i > 0; i--) { - auto msg = m_midi_log.message(static_cast(i)); - add_midi_row(msg); - } + for (size_t i = start; i > end; i--) + add_midi_row(m_midi_log.message(i)); } } diff --git a/src/plugin/ui/midi_watcher.h b/src/plugin/ui/midi_watcher.h index 5c54c202..f6a41eff 100644 --- a/src/plugin/ui/midi_watcher.h +++ b/src/plugin/ui/midi_watcher.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------- // XMidiCtrl - MIDI Controller plugin for X-Plane // -// Copyright (c) 2021-2023 Marco Auer +// Copyright (c) 2021-2024 Marco Auer // // XMidiCtrl is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -39,15 +39,22 @@ class midi_watcher : public imgui_window { void create_widgets() override; private: - void add_midi_row(midi_message* in_msg); + // constants + static constexpr unsigned int c_no_msg_page {500}; - static void draw_icon(const char* in_icon, std::string_view in_text = {}); + // members + sort_mode m_log_sort_mode {sort_mode::ascending}; + unsigned int m_page {0}; sort_mode m_midi_sort_mode {sort_mode::ascending}; ImGuiTableColumnFlags m_midi_msg_flags; midi_logger& m_midi_log; + + void add_midi_row(midi_message* in_msg); + + static void draw_icon(const char* in_icon, std::string_view in_text = {}); }; } // Namespace xmidictrl diff --git a/src/plugin/ui/settings_window.cpp b/src/plugin/ui/settings_window.cpp index d72e407d..424bb31d 100644 --- a/src/plugin/ui/settings_window.cpp +++ b/src/plugin/ui/settings_window.cpp @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------- // XMidiCtrl - MIDI Controller plugin for X-Plane // -// Copyright (c) 2021-2023 Marco Auer +// Copyright (c) 2021-2024 Marco Auer // // XMidiCtrl is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -49,9 +49,6 @@ settings_window::settings_window(text_logger& in_log, environment& in_env) m_virtual_channel = env().settings().virtual_channel(); m_default_outbound_delay = env().settings().default_outbound_delay(); - m_max_text_messages = env().settings().max_text_messages(); - m_max_midi_messages = env().settings().max_midi_messages(); - m_note_name = static_cast(env().settings().note_name()); m_default_text_sort = static_cast(env().settings().default_text_sort()); @@ -267,20 +264,6 @@ void settings_window::create_tab_logging() ImGui::Checkbox("Debug Mode", &m_debug_mode); ImGui::NewLine(); - ImGui::TextUnformatted("Limit for messages:"); - ImGui::SameLine(250); - ImGui::PushItemWidth(150); - if (ImGui::InputInt(" Messages##text", &m_max_text_messages, 50, 100)) { - if (m_max_text_messages < 1) - m_max_text_messages = 1; - else if (m_max_text_messages > 5000) - m_max_text_messages = 5000; - } - - ImGui::SameLine(600); - if (ImGui::Button(" " ICON_FA_ROTATE_RIGHT " Reset to default ##text")) - m_max_text_messages = 1500; - ImGui::TextUnformatted("Default sort mode:"); ImGui::SameLine(250); ImGui::RadioButton("Ascending##text", &m_default_text_sort, 0); @@ -297,22 +280,6 @@ void settings_window::create_tab_logging() ImGui::Checkbox("Log MIDI messages", &m_log_midi); ImGui::NewLine(); - if (m_log_midi) { - ImGui::TextUnformatted("Limit for messages:"); - ImGui::SameLine(250); - ImGui::PushItemWidth(150); - if (ImGui::InputInt(" Messages##midi", &m_max_midi_messages, 50, 100)) { - if (m_max_midi_messages < 1) - m_max_midi_messages = 1; - else if (m_max_midi_messages > 5000) - m_max_midi_messages = 5000; - } - } - - ImGui::SameLine(600); - if (ImGui::Button(" " ICON_FA_ROTATE_RIGHT " Reset to default ##midi")) - m_max_midi_messages = 150; - ImGui::TextUnformatted("Default sort mode:"); ImGui::SameLine(250); ImGui::RadioButton("Ascending##midi", &m_default_midi_sort, 0); @@ -414,9 +381,6 @@ void settings_window::save_settings() env().settings().set_virtual_channel(m_virtual_channel); env().settings().set_default_outbound_delay(m_default_outbound_delay); - env().settings().set_max_text_messages(m_max_text_messages); - env().settings().set_max_midi_messages(m_max_midi_messages); - env().settings().set_note_name(static_cast(m_note_name)); env().settings().set_default_text_sort(static_cast(m_default_text_sort)); diff --git a/src/plugin/ui/settings_window.h b/src/plugin/ui/settings_window.h index 9e2bf828..a48dfa0b 100644 --- a/src/plugin/ui/settings_window.h +++ b/src/plugin/ui/settings_window.h @@ -49,9 +49,6 @@ class settings_window : public imgui_window { int m_virtual_channel; float m_default_outbound_delay; - int m_max_text_messages; - int m_max_midi_messages; - int m_note_name; int m_default_text_sort;