diff --git a/source/lib/common/debug/logging.cpp b/source/lib/common/debug/logging.cpp
deleted file mode 100644
index a9a151574..000000000
--- a/source/lib/common/debug/logging.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * This source file is a part of the Tactile map editor.
- *
- * Copyright (C) 2023 Albin Johansson
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 this program. If not, see .
- */
-
-#include "logging.hpp"
-
-#include // time
-#include // move
-
-#include
-#include
-#include
-#include
-#include
-
-#include "common/debug/panic.hpp"
-#include "common/predef.hpp"
-#include "common/type/chrono.hpp"
-#include "common/type/deque.hpp"
-#include "common/type/ptr.hpp"
-#include "common/type/set.hpp"
-#include "io/directories.hpp"
-
-namespace tactile {
-namespace {
-
-using LogFilterSet = Set;
-
-struct LogEntry final {
- spdlog::level::level_enum level {};
- String msg;
-};
-
-[[nodiscard]] auto _to_filter_set(const LogFilter& filter) -> LogFilterSet
-{
- LogFilterSet filter_set;
-
- if (filter.trace) {
- filter_set.emplace(LogLevel::trace);
- }
-
- if (filter.debug) {
- filter_set.emplace(LogLevel::debug);
- }
-
- if (filter.info) {
- filter_set.emplace(LogLevel::info);
- }
-
- if (filter.warn) {
- filter_set.emplace(LogLevel::warn);
- }
-
- if (filter.error) {
- filter_set.emplace(LogLevel::err);
- }
-
- if (filter.critical) {
- filter_set.emplace(LogLevel::critical);
- }
-
- return filter_set;
-}
-
-/// Records logged messages, intended to be displayed in the log dock.
-class HistorySink final : public spdlog::sinks::base_sink {
- public:
- void sink_it_(const spdlog::details::log_msg& msg) override
- {
- const auto time = fmt::localtime(Clock::to_time_t(msg.time));
- auto processed = fmt::format("[{:%H:%M:%S}] {}", time, msg.payload);
- mHistory.push_back({msg.level, std::move(processed)});
- }
-
- void flush_() override
- {
- // Do nothing
- }
-
- void clear() { mHistory.clear(); }
-
- [[nodiscard]] auto count(const LogFilterSet& set) const -> usize
- {
- usize count = 0;
-
- for (const auto& [level, str]: mHistory) {
- if (set.contains(level)) {
- ++count;
- }
- }
-
- return count;
- }
-
- /// Complexity: O(NlogN)
- void visit_logged_message_range(const LogFilterSet& set,
- const usize filtered_begin_index,
- const usize filtered_end_index,
- const LoggedMessageVisitorFn& fn) const
- {
- usize filtered_index = 0;
- for (const auto& [level, msg]: mHistory) {
- if (filtered_index >= filtered_end_index) {
- break;
- }
-
- if (set.contains(level)) {
- if (filtered_index >= filtered_begin_index) {
- fn(level, msg);
- }
- ++filtered_index;
- }
- }
- }
-
- private:
- Deque mHistory;
-};
-
-inline Shared gHistorySink;
-
-} // namespace
-
-void init_logger()
-{
- const auto path = get_persistent_file_dir() / "logs" / "tactile_log.txt";
-
- auto cs = std::make_shared();
- auto fs = std::make_shared(path.string(), true);
- gHistorySink = std::make_shared();
-
- const spdlog::sinks_init_list sinks {cs, fs, gHistorySink};
-
- auto logger = std::make_shared("tactile", sinks);
- logger->set_pattern("%^[%L][%T.%e]%$ %v");
- logger->flush_on(LogLevel::critical);
-
- spdlog::set_default_logger(logger);
- spdlog::set_level(kIsDebugBuild ? LogLevel::trace : LogLevel::info);
-
- spdlog::info("Tactile version {} ({} build)",
- TACTILE_VERSION_STRING,
- TACTILE_DEBUG ? "Unoptimized" : "Optimized");
-
- const auto time = fmt::localtime(std::time(nullptr));
- spdlog::info("Today is {:%A %Y-%m-%d}", time);
-}
-
-void clear_log_history()
-{
- gHistorySink->clear();
-}
-
-auto count_matching_log_entries(const LogFilter& filter) -> usize
-{
- const auto filter_set = _to_filter_set(filter);
- return gHistorySink->count(filter_set);
-}
-
-void visit_logged_message_range(const LogFilter& filter,
- const usize begin_index,
- const usize end_index,
- const LoggedMessageVisitorFn& fn)
-{
- const auto filter_set = _to_filter_set(filter);
- gHistorySink->visit_logged_message_range(filter_set, begin_index, end_index, fn);
-}
-
-} // namespace tactile
diff --git a/source/lib/common/debug/logging.hpp b/source/lib/common/debug/logging.hpp
deleted file mode 100644
index f107aeb0d..000000000
--- a/source/lib/common/debug/logging.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This source file is a part of the Tactile map editor.
- *
- * Copyright (C) 2023 Albin Johansson
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 this program. If not, see .
- */
-
-#pragma once
-
-#include
-
-#include "common/primitives.hpp"
-#include "common/predef.hpp"
-#include "common/type/func.hpp"
-#include "common/type/string.hpp"
-
-namespace tactile {
-
-struct LogFilter final {
- bool trace : 1 {TACTILE_DEBUG};
- bool debug : 1 {TACTILE_DEBUG};
- bool info : 1 {true};
- bool warn : 1 {true};
- bool error : 1 {true};
- bool critical : 1 {true};
-};
-
-using LogLevel = spdlog::level::level_enum;
-using LoggedMessageVisitorFn = Func;
-
-/// Initializes the logger, this must be called before any logging takes place.
-void init_logger();
-
-/// Clears the entire log history.
-void clear_log_history();
-
-/// Returns the amount of logged messages that satisfy the provided filter.
-[[nodiscard]] auto count_matching_log_entries(const LogFilter& filter) -> usize;
-
-/// Invokes a callback for a range of logged messages matching the provided filter.
-void visit_logged_message_range(const LogFilter& filter,
- usize begin_index,
- usize end_index,
- const LoggedMessageVisitorFn& fn);
-
-} // namespace tactile
diff --git a/source/lib/engine/engine.cpp b/source/lib/engine/engine.cpp
index a7a45e6ac..3ca2006f9 100644
--- a/source/lib/engine/engine.cpp
+++ b/source/lib/engine/engine.cpp
@@ -29,11 +29,13 @@
#include "backend/gl/gl_backend.hpp"
#include "backend/null/null_backend.hpp"
#include "common/debug/assert.hpp"
-#include "common/debug/logging.hpp"
#include "common/debug/stacktrace.hpp"
#include "common/fmt/stacktrace_formatter.hpp"
+#include "engine/app_delegate.hpp"
#include "engine/platform/window.hpp"
#include "io/directories.hpp"
+#include "model/locator.hpp"
+#include "model/services/logging_service.hpp"
namespace tactile {
@@ -54,7 +56,11 @@ Engine::Engine(const BackendAPI api)
: mAPI {api}
{
std::set_terminate(&on_terminate);
- init_logger();
+
+ mLoggingService = std::make_unique();
+ mLoggingService->install_logger();
+
+ Locator::reset(mLoggingService.get());
mProtobuf.emplace();
auto& sdl = mSDL.emplace(mAPI);
@@ -80,6 +86,8 @@ Engine::Engine(const BackendAPI api)
spdlog::debug("[IO] Persistent file directory: {}", get_persistent_file_dir());
}
+Engine::~Engine() noexcept = default;
+
void Engine::start()
{
TACTILE_ASSERT(mBackend != nullptr);
diff --git a/source/lib/engine/engine.hpp b/source/lib/engine/engine.hpp
index ef24f5a55..35031d4ca 100644
--- a/source/lib/engine/engine.hpp
+++ b/source/lib/engine/engine.hpp
@@ -21,22 +21,27 @@
#include
-#include "backend/backend.hpp"
#include "common/enum/backend_api.hpp"
+#include "common/macros.hpp"
#include "common/predef.hpp"
#include "common/type/maybe.hpp"
#include "common/type/ptr.hpp"
-#include "engine/app_delegate.hpp"
#include "engine/platform/imgui_context.hpp"
#include "engine/platform/protobuf_context.hpp"
#include "engine/platform/sdl_context.hpp"
namespace tactile {
+TACTILE_FWD_DECLARE_CLASS(LoggingService)
+TACTILE_FWD_DECLARE_CLASS(Backend)
+TACTILE_FWD_DECLARE_CLASS(AppDelegate)
+
class Engine final {
public:
explicit Engine(BackendAPI api);
+ ~Engine() noexcept;
+
void start();
void set_app_delegate(Unique app);
@@ -45,6 +50,7 @@ class Engine final {
private:
BackendAPI mAPI;
+ Unique mLoggingService;
Maybe mProtobuf;
Maybe mSDL;
Maybe mImGui;
diff --git a/source/lib/model/services/logging_service.cpp b/source/lib/model/services/logging_service.cpp
new file mode 100644
index 000000000..fadb1bd82
--- /dev/null
+++ b/source/lib/model/services/logging_service.cpp
@@ -0,0 +1,155 @@
+/*
+ * This source file is a part of the Tactile map editor.
+ *
+ * Copyright (C) 2023 Albin Johansson
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see .
+ */
+
+#include "logging_service.hpp"
+
+#include // time
+#include // move
+
+#include
+#include
+#include
+#include
+#include
+
+#include "common/debug/panic.hpp"
+#include "common/type/chrono.hpp"
+#include "io/directories.hpp"
+
+namespace tactile {
+namespace {
+
+[[nodiscard]] auto _convert_log_level(const spdlog::level::level_enum level)
+ -> LogLevelBits
+{
+ switch (level) {
+ case spdlog::level::trace:
+ return LOG_LEVEL_TRACE;
+
+ case spdlog::level::debug:
+ return LOG_LEVEL_DEBUG;
+
+ case spdlog::level::info:
+ return LOG_LEVEL_INFO;
+
+ case spdlog::level::warn:
+ return LOG_LEVEL_WARNING;
+
+ case spdlog::level::err:
+ return LOG_LEVEL_ERROR;
+
+ case spdlog::level::critical:
+ return LOG_LEVEL_CRITICAL;
+
+ default:
+ throw TactileError {"Unsupported log level"};
+ }
+}
+
+} // namespace
+
+void LogHistorySink::sink_it_(const spdlog::details::log_msg& msg)
+{
+ const auto time = fmt::localtime(Clock::to_time_t(msg.time));
+
+ const auto level = _convert_log_level(msg.level);
+ auto formatted_msg = fmt::format("[{:%H:%M:%S}] {}", time, msg.payload);
+
+ mMessages.push_back(LogEntry {level, std::move(formatted_msg)});
+}
+
+void LogHistorySink::flush_()
+{
+ // Do nothing
+}
+
+void LogHistorySink::clear()
+{
+ mMessages.clear();
+}
+
+void LoggingService::install_logger()
+{
+ using ColorSink = spdlog::sinks::stdout_color_sink_st;
+ using FileSink = spdlog::sinks::basic_file_sink_st;
+
+ const auto log_file_path = get_persistent_file_dir() / "logs" / "tactile_log.txt";
+
+ auto color_sink = std::make_shared();
+ auto file_sink = std::make_shared(log_file_path.string(), true);
+ mHistorySink = std::make_shared();
+
+ const spdlog::sinks_init_list sinks {color_sink, file_sink, mHistorySink};
+
+ auto logger = std::make_shared("tactile", sinks);
+ logger->set_pattern("%^[%L][%T.%e]%$ %v");
+ logger->flush_on(spdlog::level::critical);
+
+ spdlog::set_default_logger(logger);
+ spdlog::set_level(kIsDebugBuild ? spdlog::level::trace : spdlog::level::info);
+
+ spdlog::info("Tactile version {} ({} build)",
+ TACTILE_VERSION_STRING,
+ TACTILE_DEBUG ? "Unoptimized" : "Optimized");
+
+ const auto time = fmt::localtime(std::time(nullptr));
+ spdlog::info("Today is {:%A %Y-%m-%d}", time);
+}
+
+void LoggingService::clear_history()
+{
+ mHistorySink->clear();
+}
+
+void LoggingService::each_logged_message(const usize filtered_begin_index,
+ const usize filtered_end_index,
+ const LogLevelFlags log_level_flags,
+ const LogMessageCallback& callback) const
+{
+ usize filtered_index = 0;
+ for (const auto& [level, msg]: mHistorySink->get_messages()) {
+ if (filtered_index >= filtered_end_index) {
+ break;
+ }
+
+ if (level & log_level_flags) {
+ if (filtered_index >= filtered_begin_index) {
+ callback(level, msg);
+ }
+
+ ++filtered_index;
+ }
+ }
+}
+
+auto LoggingService::count_logged_messages(const LogLevelFlags log_level_flags) const
+ -> usize
+{
+ usize count = 0;
+
+ for (const auto& [level, msg]: mHistorySink->get_messages()) {
+ if (level & log_level_flags) {
+ ++count;
+ }
+ }
+
+ return count;
+}
+
+} // namespace tactile
diff --git a/source/lib/model/services/logging_service.hpp b/source/lib/model/services/logging_service.hpp
new file mode 100644
index 000000000..0a1265933
--- /dev/null
+++ b/source/lib/model/services/logging_service.hpp
@@ -0,0 +1,109 @@
+/*
+ * This source file is a part of the Tactile map editor.
+ *
+ * Copyright (C) 2023 Albin Johansson
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+#include "common/predef.hpp"
+#include "common/primitives.hpp"
+#include "common/type/deque.hpp"
+#include "common/type/func.hpp"
+#include "common/type/ptr.hpp"
+#include "common/type/string.hpp"
+
+namespace tactile {
+
+enum LogLevelBits : uint32 {
+ LOG_LEVEL_TRACE = 1u << 0u,
+ LOG_LEVEL_DEBUG = 1u << 1u,
+ LOG_LEVEL_INFO = 1u << 2u,
+ LOG_LEVEL_WARNING = 1u << 3u,
+ LOG_LEVEL_ERROR = 1u << 4u,
+ LOG_LEVEL_CRITICAL = 1u << 5u,
+};
+
+using LogLevelFlags = uint32;
+
+inline constexpr LogLevelFlags kAllLogLevels = LOG_LEVEL_TRACE | LOG_LEVEL_DEBUG |
+ LOG_LEVEL_INFO | LOG_LEVEL_WARNING |
+ LOG_LEVEL_ERROR | LOG_LEVEL_CRITICAL;
+
+struct LogEntry final {
+ LogLevelBits level;
+ String msg;
+};
+
+class LogHistorySink final :
+ public spdlog::sinks::base_sink {
+ public:
+ void sink_it_(const spdlog::details::log_msg& msg) override;
+
+ void flush_() override;
+
+ void clear();
+
+ [[nodiscard]] auto get_messages() const -> const Deque& { return mMessages; }
+
+ private:
+ Deque mMessages;
+};
+
+class LoggingService final {
+ public:
+ using LogMessageCallback = Func;
+
+ /// Installs the global logger.
+ void install_logger();
+
+ /// Clears the in-memory history of logged messages.
+ void clear_history();
+
+ /**
+ * Visits each logged message that satisfies the specified log level filter and range.
+ *
+ * \complexity O(N)
+ *
+ * \param filtered_begin_index the index of the first passing message to include.
+ * \param filtered_end_index the index of the last passing message to include.
+ * \param log_level_flags a bitmask of log levels used as a message filter.
+ * \param callback a callback invoked for each passing message.
+ */
+ void each_logged_message(usize filtered_begin_index,
+ usize filtered_end_index,
+ LogLevelFlags log_level_flags,
+ const LogMessageCallback& callback) const;
+
+ /**
+ * Returns the number of messages that match the specified log levels.
+ *
+ * \complexity O(N)
+ *
+ * \param log_level_flags a bitmask of log levels used as a message filter.
+ *
+ * \return the number of matching messages.
+ */
+ [[nodiscard]] auto count_logged_messages(LogLevelFlags log_level_flags) const -> usize;
+
+ private:
+ Shared mHistorySink;
+};
+
+} // namespace tactile
diff --git a/source/lib/ui/dock/log/log_dock.cpp b/source/lib/ui/dock/log/log_dock.cpp
index d4a337478..a189e0da5 100644
--- a/source/lib/ui/dock/log/log_dock.cpp
+++ b/source/lib/ui/dock/log/log_dock.cpp
@@ -21,72 +21,84 @@
#include
-#include "common/debug/logging.hpp"
#include "common/type/hash_map.hpp"
#include "common/util/lookup.hpp"
#include "model/events/setting_events.hpp"
#include "model/i18n/language_system.hpp"
+#include "model/locator.hpp"
#include "ui/widget/scoped.hpp"
#include "ui/widget/widgets.hpp"
namespace tactile {
namespace {
-const HashMap kLogLevelColors = {
- {LogLevel::trace, ImVec4 {0.93f, 0.51f, 0.93f, 1.00f}},
- {LogLevel::debug, ImVec4 {0.50f, 1.00f, 0.70f, 1.00f}},
- {LogLevel::info, ImVec4 {1.00f, 1.00f, 1.00f, 1.00f}},
- {LogLevel::warn, ImVec4 {1.00f, 1.00f, 0.00f, 1.00f}},
- {LogLevel::err, ImVec4 {1.00f, 0.40f, 0.40f, 1.00f}},
- {LogLevel::critical, ImVec4 {1.00f, 0.00f, 0.00f, 1.00f}},
+inline constexpr auto kLogDockContextMenuID = "##LogDockWindowPopup";
+
+const HashMap kLogLevelColors = {
+ {LOG_LEVEL_TRACE, ImVec4 {0.93f, 0.51f, 0.93f, 1.00f}},
+ {LOG_LEVEL_DEBUG, ImVec4 {0.50f, 1.00f, 0.70f, 1.00f}},
+ {LOG_LEVEL_INFO, ImVec4 {1.00f, 1.00f, 1.00f, 1.00f}},
+ {LOG_LEVEL_WARNING, ImVec4 {1.00f, 1.00f, 0.00f, 1.00f}},
+ {LOG_LEVEL_ERROR, ImVec4 {1.00f, 0.40f, 0.40f, 1.00f}},
+ {LOG_LEVEL_CRITICAL, ImVec4 {1.00f, 0.00f, 0.00f, 1.00f}},
};
-void _push_message_filter_checkboxes(const Strings& strings, LogDockState& state)
+void _push_filter_options(const Strings& strings, LogDockState& state)
{
- {
- bool value = state.log_filter.trace;
- ImGui::Checkbox(strings.misc.log_trace_filter.c_str(), &value);
- state.log_filter.trace = value;
+ bool include_trace = state.log_filter & LOG_LEVEL_TRACE;
+ bool include_debug = state.log_filter & LOG_LEVEL_DEBUG;
+ bool include_info = state.log_filter & LOG_LEVEL_INFO;
+ bool include_warning = state.log_filter & LOG_LEVEL_WARNING;
+ bool include_error = state.log_filter & LOG_LEVEL_ERROR;
+ bool include_critical = state.log_filter & LOG_LEVEL_CRITICAL;
+
+ if (const ui::Menu filter_menu {strings.misc.filter.c_str()}; filter_menu.is_open()) {
+ ImGui::MenuItem(strings.misc.log_trace_filter.c_str(), nullptr, &include_trace);
+ ImGui::MenuItem(strings.misc.log_debug_filter.c_str(), nullptr, &include_debug);
+ ImGui::MenuItem(strings.misc.log_info_filter.c_str(), nullptr, &include_info);
+ ImGui::MenuItem(strings.misc.log_warn_filter.c_str(), nullptr, &include_warning);
+ ImGui::MenuItem(strings.misc.log_error_filter.c_str(), nullptr, &include_error);
+ ImGui::MenuItem(strings.misc.log_critical_filter.c_str(), nullptr, &include_critical);
}
- ImGui::SameLine();
+ state.log_filter = 0;
- {
- bool value = state.log_filter.debug;
- ImGui::Checkbox(strings.misc.log_debug_filter.c_str(), &value);
- state.log_filter.debug = value;
+ if (include_trace) {
+ state.log_filter |= LOG_LEVEL_TRACE;
}
- ImGui::SameLine();
-
- {
- bool value = state.log_filter.info;
- ImGui::Checkbox(strings.misc.log_info_filter.c_str(), &value);
- state.log_filter.info = value;
+ if (include_debug) {
+ state.log_filter |= LOG_LEVEL_DEBUG;
}
- ImGui::SameLine();
+ if (include_info) {
+ state.log_filter |= LOG_LEVEL_INFO;
+ }
- {
- bool value = state.log_filter.warn;
- ImGui::Checkbox(strings.misc.log_warn_filter.c_str(), &value);
- state.log_filter.warn = value;
+ if (include_warning) {
+ state.log_filter |= LOG_LEVEL_WARNING;
}
- ImGui::SameLine();
+ if (include_error) {
+ state.log_filter |= LOG_LEVEL_ERROR;
+ }
- {
- bool value = state.log_filter.error;
- ImGui::Checkbox(strings.misc.log_error_filter.c_str(), &value);
- state.log_filter.error = value;
+ if (include_critical) {
+ state.log_filter |= LOG_LEVEL_CRITICAL;
}
+}
- ImGui::SameLine();
+void _push_dock_context_menu(const Strings& strings, LogDockState& state)
+{
+ if (const auto popup = ui::Popup::for_window(kLogDockContextMenuID); popup.is_open()) {
+ _push_filter_options(strings, state);
- {
- bool value = state.log_filter.critical;
- ImGui::Checkbox(strings.misc.log_critical_filter.c_str(), &value);
- state.log_filter.critical = value;
+ ImGui::Separator();
+
+ if (ImGui::MenuItem(strings.action.clear_log.c_str())) {
+ auto& logging_service = Locator::get();
+ logging_service.clear_history(); // TODO event
+ }
}
}
@@ -112,22 +124,22 @@ void _push_logged_message_legend_overlay(const Strings& strings)
if (const ui::Window overlay {"##LegendOverlay", overlay_window_flags};
overlay.is_open()) {
- ImGui::TextColored(lookup_in(kLogLevelColors, LogLevel::trace),
+ ImGui::TextColored(lookup_in(kLogLevelColors, LOG_LEVEL_TRACE),
"%s",
strings.misc.log_trace_filter.c_str());
- ImGui::TextColored(lookup_in(kLogLevelColors, LogLevel::debug),
+ ImGui::TextColored(lookup_in(kLogLevelColors, LOG_LEVEL_DEBUG),
"%s",
strings.misc.log_debug_filter.c_str());
- ImGui::TextColored(lookup_in(kLogLevelColors, LogLevel::info),
+ ImGui::TextColored(lookup_in(kLogLevelColors, LOG_LEVEL_INFO),
"%s",
strings.misc.log_info_filter.c_str());
- ImGui::TextColored(lookup_in(kLogLevelColors, LogLevel::warn),
+ ImGui::TextColored(lookup_in(kLogLevelColors, LOG_LEVEL_WARNING),
"%s",
strings.misc.log_warn_filter.c_str());
- ImGui::TextColored(lookup_in(kLogLevelColors, LogLevel::err),
+ ImGui::TextColored(lookup_in(kLogLevelColors, LOG_LEVEL_ERROR),
"%s",
strings.misc.log_error_filter.c_str());
- ImGui::TextColored(lookup_in(kLogLevelColors, LogLevel::critical),
+ ImGui::TextColored(lookup_in(kLogLevelColors, LOG_LEVEL_CRITICAL),
"%s",
strings.misc.log_critical_filter.c_str());
}
@@ -137,8 +149,9 @@ void _push_logged_message_view(const Strings& strings,
const usize message_count,
LogDockState& state)
{
- const ui::StyleColor child_bg {ImGuiCol_ChildBg, {0.1f, 0.1f, 0.1f, 0.75f}};
+ const auto& logging_service = Locator::get();
+ const ui::StyleColor child_bg {ImGuiCol_ChildBg, {0.1f, 0.1f, 0.1f, 0.75f}};
const auto child_flags = ImGuiWindowFlags_AlwaysVerticalScrollbar |
ImGuiWindowFlags_HorizontalScrollbar |
ImGuiWindowFlags_AlwaysAutoResize;
@@ -148,13 +161,15 @@ void _push_logged_message_view(const Strings& strings,
clipper.Begin(static_cast(message_count));
while (clipper.Step()) {
- visit_logged_message_range(state.log_filter,
- static_cast(clipper.DisplayStart),
- static_cast(clipper.DisplayEnd),
- [](const LogLevel level, const String& msg) {
- const auto& color = lookup_in(kLogLevelColors, level);
- ImGui::TextColored(color, "%s", msg.c_str());
- });
+ auto show_colored_message = [](const LogLevelBits level, StringView msg) {
+ const auto& color = lookup_in(kLogLevelColors, level);
+ ImGui::TextColored(color, "%s", msg.data());
+ };
+
+ logging_service.each_logged_message(static_cast(clipper.DisplayStart),
+ static_cast(clipper.DisplayEnd),
+ state.log_filter,
+ show_colored_message);
}
// Makes the log follow new messages, unless the user explicitly scrolls up
@@ -189,9 +204,9 @@ void push_log_dock_widget(ModelView& model, LogDockState& state)
state.has_focus = dock.has_focus(ImGuiFocusedFlags_RootAndChildWindows);
if (dock.is_open()) {
- _push_message_filter_checkboxes(strings, state);
+ const auto& logging_service = Locator::get();
+ const auto message_count = logging_service.count_logged_messages(state.log_filter);
- const auto message_count = count_matching_log_entries(state.log_filter);
if (message_count != 0u) {
_push_logged_message_view(strings, message_count, state);
}
@@ -199,11 +214,11 @@ void push_log_dock_widget(ModelView& model, LogDockState& state)
ui::push_centered_label(strings.misc.log_no_messages_match_filter.c_str());
}
- if (auto popup = ui::Popup::for_window("##LogDockPopup"); popup.is_open()) {
- if (ImGui::MenuItem(strings.action.clear_log.c_str())) {
- clear_log_history();
- }
+ if (dock.is_hovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
+ ImGui::OpenPopup(kLogDockContextMenuID);
}
+
+ _push_dock_context_menu(strings, state);
}
}
diff --git a/source/lib/ui/dock/log/log_dock.hpp b/source/lib/ui/dock/log/log_dock.hpp
index c8dbda2aa..59644a71e 100644
--- a/source/lib/ui/dock/log/log_dock.hpp
+++ b/source/lib/ui/dock/log/log_dock.hpp
@@ -19,14 +19,15 @@
#pragma once
-#include "common/debug/logging.hpp"
+#include "common/primitives.hpp"
#include "common/type/ecs.hpp"
#include "model/model_view.hpp"
+#include "model/services/logging_service.hpp"
namespace tactile {
struct LogDockState final {
- LogFilter log_filter;
+ uint32 log_filter {kAllLogLevels};
bool has_focus {};
};