You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1223 lines
42 KiB
1223 lines
42 KiB
// License: Apache 2.0. See LICENSE file in root directory.
|
|
// Copyright(c) 2020 Intel Corporation. All Rights Reserved.
|
|
|
|
#include <glad/glad.h>
|
|
#include "output-model.h"
|
|
#include <rs-config.h>
|
|
#include "ux-window.h"
|
|
#include "device-model.h"
|
|
#include "os.h"
|
|
|
|
#include <imgui_internal.h>
|
|
#include <librealsense2/hpp/rs_internal.hpp>
|
|
|
|
#include <fstream>
|
|
#include <iterator>
|
|
|
|
using namespace rs2;
|
|
using namespace rsutils::string;
|
|
|
|
void output_model::thread_loop()
|
|
{
|
|
while (!to_stop)
|
|
{
|
|
std::vector<rs2::device> dev_copy;
|
|
{
|
|
std::lock_guard<std::mutex> lock(devices_mutex);
|
|
dev_copy = devices;
|
|
}
|
|
if (enable_firmware_logs)
|
|
for (auto&& dev : dev_copy)
|
|
{
|
|
try
|
|
{
|
|
if (auto fwlogger = dev.as<rs2::firmware_logger>())
|
|
{
|
|
bool has_parser = false;
|
|
std::string hwlogger_xml = config_file::instance().get(configurations::viewer::hwlogger_xml);
|
|
std::ifstream f(hwlogger_xml.c_str());
|
|
if (f.good())
|
|
{
|
|
try
|
|
{
|
|
std::string str((std::istreambuf_iterator<char>(f)),
|
|
std::istreambuf_iterator<char>());
|
|
fwlogger.init_parser(str);
|
|
has_parser = true;
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
add_log( RS2_LOG_SEVERITY_WARN,
|
|
__FILE__,
|
|
__LINE__,
|
|
rsutils::string::from()
|
|
<< "Invalid Hardware Logger XML at '" << hwlogger_xml << "': " << ex.what()
|
|
<< "\nEither configure valid XML or remove it" );
|
|
}
|
|
}
|
|
|
|
auto message = fwlogger.create_message();
|
|
while (fwlogger.get_firmware_log(message))
|
|
{
|
|
auto parsed = fwlogger.create_parsed_message();
|
|
auto parsed_ok = false;
|
|
|
|
if (has_parser)
|
|
{
|
|
if (fwlogger.parse_log(message, parsed))
|
|
{
|
|
parsed_ok = true;
|
|
|
|
add_log( message.get_severity(),
|
|
parsed.file_name(),
|
|
parsed.line(),
|
|
rsutils::string::from()
|
|
<< "FW-LOG [" << parsed.thread_name() << "] " << parsed.message() );
|
|
}
|
|
}
|
|
|
|
if (!parsed_ok)
|
|
{
|
|
std::stringstream ss;
|
|
for (auto& elem : message.data())
|
|
ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(elem) << " ";
|
|
add_log(message.get_severity(), __FILE__, 0, ss.str());
|
|
}
|
|
if (!enable_firmware_logs && fwlogger.get_number_of_fw_logs() == 0)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch(const std::exception& ex)
|
|
{
|
|
add_log( RS2_LOG_SEVERITY_WARN,
|
|
__FILE__,
|
|
__LINE__,
|
|
rsutils::string::from() << "Failed to fetch firmware logs: " << ex.what() );
|
|
}
|
|
}
|
|
// FW define the logs polling intervals to be no less than 100msec to cope with limited resources.
|
|
// At the same time 100 msec should guarantee no log drops
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
}
|
|
|
|
output_model::~output_model()
|
|
{
|
|
to_stop = 1;
|
|
fw_logger.join();
|
|
}
|
|
|
|
output_model::output_model() : fw_logger([this](){ thread_loop(); }) , incoming_log_queue(100)
|
|
{
|
|
is_output_open = config_file::instance().get_or_default(
|
|
configurations::viewer::output_open, false);
|
|
search_line = config_file::instance().get_or_default(
|
|
configurations::viewer::search_term, std::string(""));
|
|
is_dashboard_open = config_file::instance().get_or_default(
|
|
configurations::viewer::dashboard_open, true );
|
|
|
|
if (search_line != "") search_open = true;
|
|
|
|
available_dashboards["Frame Drops per Second"] = [&](std::string name){
|
|
return std::make_shared<frame_drops_dashboard>(name, &number_of_drops, &total_frames);
|
|
};
|
|
|
|
auto front = available_dashboards.begin();
|
|
dashboards.push_back(front->second(front->first));
|
|
}
|
|
|
|
bool output_model::round_indicator(ux_window& win, std::string icon,
|
|
int count, ImVec4 color, std::string tooltip, bool& highlighted, std::string suffix)
|
|
{
|
|
std::stringstream ss;
|
|
ss << icon;
|
|
if (count > 0) ss << " " << count << suffix;
|
|
auto size = ImGui::CalcTextSize(ss.str().c_str());
|
|
|
|
if (count == 0 || (!is_output_open && !highlighted)) {
|
|
color = dark_sensor_bg;
|
|
ImGui::PushStyleColor(ImGuiCol_Text, header_color);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, header_color);
|
|
}
|
|
else
|
|
{
|
|
if (!highlighted)
|
|
{
|
|
color = saturate(color, 0.3f);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, white);
|
|
}
|
|
else
|
|
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);
|
|
}
|
|
|
|
auto pos = ImGui::GetCursorScreenPos();
|
|
ImGui::GetWindowDrawList()->AddRectFilled({ pos.x, pos.y + 3 },
|
|
{ pos.x + size.x + 15, pos.y + 27 }, ImColor(color), 12, 15);
|
|
|
|
auto res = ImGui::Button(ss.str().c_str(), ImVec2(size.x + 15, 28));
|
|
if (count > 0 && ImGui::IsItemHovered())
|
|
{
|
|
highlighted = true;
|
|
win.link_hovered();
|
|
ImGui::SetTooltip("%s", tooltip.c_str());
|
|
}
|
|
else highlighted = false;
|
|
|
|
ImGui::PopStyleColor(2);
|
|
|
|
return res;
|
|
}
|
|
|
|
void output_model::open(ux_window& win)
|
|
{
|
|
is_output_open = true;
|
|
config_file::instance().set(configurations::viewer::output_open, true);
|
|
default_log_h = static_cast<int>((win.height() - 100) / 2);
|
|
new_log = true;
|
|
}
|
|
|
|
void output_model::draw(ux_window& win, rect view_rect, device_models_list & device_models)
|
|
{
|
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, scrollbar_bg);
|
|
|
|
auto x = view_rect.x;
|
|
auto y = view_rect.y;
|
|
auto w = view_rect.w;
|
|
auto h = view_rect.h;
|
|
|
|
auto flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar |
|
|
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings;
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, sensor_bg);
|
|
ImGui::PushStyleColor(ImGuiCol_Button, transparent);
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, transparent);
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, transparent);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
|
|
|
|
ImGui::PushFont(win.get_font());
|
|
ImGui::SetNextWindowPos({ x, y });
|
|
ImGui::SetNextWindowSize({ w, h });
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(3, 3));
|
|
|
|
ImGui::Begin("Output", nullptr, flags);
|
|
|
|
ImGui::SetCursorPosX(w - 31);
|
|
if (!is_output_open)
|
|
{
|
|
if (ImGui::Button(u8"\uF139", ImVec2(28, 28)))
|
|
{
|
|
open(win);
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
win.link_hovered();
|
|
ImGui::SetTooltip("%s", "Open Debug Console Window");
|
|
}
|
|
|
|
if (default_log_h.value() != 36)
|
|
default_log_h = 36;
|
|
}
|
|
else
|
|
{
|
|
if (ImGui::Button(u8"\uF13A", ImVec2(28, 28)))
|
|
{
|
|
is_output_open = false;
|
|
config_file::instance().set(configurations::viewer::output_open, false);
|
|
default_log_h = 36;
|
|
search_open = false;
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
win.link_hovered();
|
|
ImGui::SetTooltip("%s", "Collapse Debug Console Window");
|
|
}
|
|
|
|
int h_val = (int)((win.height() - 100) / 2);
|
|
if (default_log_h.value() != h_val)
|
|
default_log_h = h_val;
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPosX(5);
|
|
|
|
if (errors_selected) errors_highlighted = true;
|
|
if (round_indicator(win, u8"\uF057", number_of_errors, redish, "Instances of logged errors", errors_highlighted))
|
|
{
|
|
errors_selected = !errors_selected;
|
|
open(win);
|
|
}
|
|
ImGui::SameLine();
|
|
|
|
if (warnings_selected) warnings_highlighted = true;
|
|
if (round_indicator(win, u8"\uF071", number_of_warnings, orange, "Instances of logged warnings", warnings_highlighted))
|
|
{
|
|
warnings_selected = !warnings_selected;
|
|
open(win);
|
|
}
|
|
ImGui::SameLine();
|
|
|
|
if (info_selected) info_highlighted = true;
|
|
if (round_indicator(win, u8"\uF05A", number_of_info, greenish, "Instances of logged info messages", info_highlighted))
|
|
{
|
|
info_selected = !info_selected;
|
|
open(win);
|
|
}
|
|
ImGui::SameLine();
|
|
|
|
if (!is_output_open || search_open)
|
|
{
|
|
ImGui::PushStyleColor(ImGuiCol_Text, header_color);
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
|
|
}
|
|
bool focus_search = false;
|
|
if (ImGui::Button(u8"\uF002", ImVec2(28, 28)))
|
|
{
|
|
focus_search = true;
|
|
search_open = true;
|
|
open(win);
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
win.link_hovered();
|
|
ImGui::SetTooltip("%s", "Search through logs");
|
|
}
|
|
ImGui::PopStyleColor(1);
|
|
ImGui::SameLine();
|
|
|
|
auto curr_x = ImGui::GetCursorPosX();
|
|
ImGui::SetCursorPosX(curr_x - 5);
|
|
|
|
|
|
int percent = total_frames ? (int)(100 * ((double)number_of_drops / (total_frames))) : 0;
|
|
|
|
std::stringstream ss;
|
|
ss << u8"\uF043";
|
|
if (percent) ss << " " << percent << "%";
|
|
auto size = ImGui::CalcTextSize(ss.str().c_str());
|
|
|
|
char buff[1024];
|
|
memcpy(buff, search_line.c_str(), search_line.size());
|
|
buff[search_line.size()] = 0;
|
|
|
|
auto actual_search_width = w - size.x - 100 - curr_x;
|
|
if (focus_search) search_width = (int)(actual_search_width);
|
|
|
|
if (search_open && search_width.value() != actual_search_width)
|
|
search_width = (int)(actual_search_width);
|
|
|
|
// if (is_output_open && search_width < 1)
|
|
// {
|
|
// search_open = true;
|
|
// }
|
|
|
|
if (search_open)
|
|
{
|
|
ImGui::PushFont(win.get_monofont());
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4);
|
|
ImGui::PushItemWidth(static_cast<float>(search_width));
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, regular_blue);
|
|
if (ImGui::InputText("##SearchInLogs",buff, 1023))
|
|
{
|
|
search_line = buff;
|
|
config_file::instance().set(configurations::viewer::search_term, search_line);
|
|
}
|
|
if (focus_search) ImGui::SetKeyboardFocusHere();
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine();
|
|
ImGui::PopStyleColor();
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4);
|
|
ImGui::PopFont();
|
|
}
|
|
|
|
ImGui::SetCursorPosX(w - size.x - 3 * 30);
|
|
|
|
if (enable_firmware_logs)
|
|
{
|
|
ImGui::PushStyleColor(ImGuiCol_Text, light_blue);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, light_blue);
|
|
}
|
|
else
|
|
{
|
|
if (is_output_open)
|
|
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
|
|
else
|
|
ImGui::PushStyleColor(ImGuiCol_Text, header_color);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);
|
|
}
|
|
|
|
if (ImGui::Button(u8"\uF2DB", ImVec2(28, 28)))
|
|
{
|
|
enable_firmware_logs = !enable_firmware_logs;
|
|
}
|
|
ImGui::PopStyleColor(2);
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
win.link_hovered();
|
|
if (enable_firmware_logs) ImGui::SetTooltip("%s", "Disable Firmware Logs");
|
|
else ImGui::SetTooltip("%s", "Enable Firmware Logs");
|
|
}
|
|
ImGui::SameLine();
|
|
|
|
|
|
if (round_indicator(win, u8"\uF043", percent, regular_blue, "Frame drops", drops_highlighted, "%"))
|
|
{
|
|
open(win);
|
|
}
|
|
|
|
if (is_output_open)
|
|
{
|
|
ImGui::SetCursorPos(ImVec2(3, 35));
|
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0));
|
|
ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, dark_sensor_bg);
|
|
|
|
const float log_area_width = w - get_dashboard_width() - 2;
|
|
|
|
ImGui::BeginChild("##LogArea",
|
|
ImVec2(log_area_width, h - 38 - ImGui::GetTextLineHeightWithSpacing() - 1), true,
|
|
ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
|
|
|
bool copy_all = false;
|
|
bool save_all = false;
|
|
std::vector<std::string> output_strings;
|
|
|
|
auto time_now = glfwGetTime();
|
|
|
|
int i = 0;
|
|
foreach_log([&](log_entry& log)
|
|
{
|
|
auto line = log.line;
|
|
if (log.line_number)
|
|
{
|
|
line = log.filename.substr(log.filename.find_last_of("/\\") + 1) + ":";
|
|
line += std::string( rsutils::string::from() << log.line_number) + " - ";
|
|
line += log.line;
|
|
}
|
|
|
|
bool ok = false;
|
|
if (info_selected || warnings_selected || errors_selected)
|
|
{
|
|
if (info_selected && log.severity <= RS2_LOG_SEVERITY_INFO) ok = true;
|
|
if (warnings_selected && log.severity == RS2_LOG_SEVERITY_WARN) ok = true;
|
|
if (errors_selected && log.severity >= RS2_LOG_SEVERITY_ERROR) ok = true;
|
|
}
|
|
else ok = true;
|
|
|
|
if (search_line != "" && to_lower(line).find(to_lower(search_line)) == std::string::npos) ok = false;
|
|
|
|
if (!ok) return;
|
|
|
|
std::stringstream ss; ss << log.timestamp << " [" << rs2_log_severity_to_string(log.severity) << "] ";
|
|
if (log.line_number) ss << log.filename << ":" << log.line_number;
|
|
ss << " - " << log.line;
|
|
std::string full = ss.str();
|
|
|
|
ImGui::PushFont(win.get_monofont());
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, regular_blue);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
|
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, transparent);
|
|
|
|
ImVec4 color = redish;
|
|
if (log.severity >= RS2_LOG_SEVERITY_ERROR)
|
|
{
|
|
color = redish;
|
|
}
|
|
else if (log.severity >= RS2_LOG_SEVERITY_WARN)
|
|
{
|
|
color = orange;
|
|
}
|
|
else
|
|
{
|
|
color = greenish;
|
|
}
|
|
|
|
auto margin = ImGui::GetTextLineHeightWithSpacing() - ImGui::GetTextLineHeight();
|
|
auto size = ImGui::CalcTextSize(line.c_str());
|
|
|
|
auto t = single_wave(static_cast<float>(time_now - log.time_added + 0.3f)) * 0.2f;
|
|
if (log.selected) t = 0.2f;
|
|
|
|
auto pos = ImGui::GetCursorScreenPos();
|
|
ImGui::GetWindowDrawList()->AddRectFilled({ pos.x, pos.y },
|
|
{ pos.x + log_area_width, pos.y + size.y + 2 * margin },
|
|
ImColor(alpha(saturate(color, 0.3f + t), 0.7f + t)));
|
|
ImGui::GetWindowDrawList()->AddLine({ pos.x, pos.y + size.y + 2 * margin },
|
|
{ pos.x + log_area_width, pos.y + size.y + 2 * margin }, ImColor(alpha(color, 0.5f)));
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 4);
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4);
|
|
ImGui::Text("%s", log.timestamp.c_str()); ImGui::SameLine();
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 4);
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4);
|
|
|
|
std::string label = rsutils::string::from() << "##log_entry" << i++;
|
|
ImGui::InputTextEx(label.c_str(),
|
|
(char*)line.data(),
|
|
static_cast<int>(line.size() + 1),
|
|
ImVec2(-1, size.y + margin),
|
|
ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_ReadOnly);
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, almost_white_bg);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, black);
|
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, light_blue);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(5,5));
|
|
label = rsutils::string::from() << "##log_entry" << i << "_context_menu";
|
|
if (ImGui::BeginPopupContextItem(label.c_str()))
|
|
{
|
|
log.selected = true;
|
|
ImGui::PushFont(win.get_font());
|
|
if (ImGui::Selectable("Copy Line")) {
|
|
glfwSetClipboardString(win, full.c_str());
|
|
}
|
|
if (ImGui::Selectable("Copy All")) {
|
|
copy_all = true;
|
|
}
|
|
if (ImGui::Selectable("Save As...")) {
|
|
save_all = true;
|
|
}
|
|
ImGui::PopFont();
|
|
ImGui::EndPopup();
|
|
}
|
|
else log.selected = false;
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor(4);
|
|
|
|
ImGui::PopStyleColor(3);
|
|
ImGui::PopFont();
|
|
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 1);
|
|
|
|
output_strings.push_back(full);
|
|
});
|
|
|
|
std::stringstream ss;
|
|
for (auto&& s : output_strings) ss << s << "\n";
|
|
if (copy_all)
|
|
glfwSetClipboardString(win, ss.str().c_str());
|
|
|
|
if (save_all)
|
|
{
|
|
if (auto fn = file_dialog_open(file_dialog_mode::save_file, "Log File\0*.log\0", nullptr, nullptr))
|
|
{
|
|
std::ofstream out(fn);
|
|
if (out.good())
|
|
{
|
|
out << ss.str();
|
|
}
|
|
out.close();
|
|
}
|
|
}
|
|
|
|
ImGui::EndChild();
|
|
ImGui::PopStyleVar();
|
|
|
|
|
|
ImGui::SetCursorPos(ImVec2(7, h - ImGui::GetTextLineHeightWithSpacing() - 2));
|
|
ImGui::Text("%s", u8"\uF120"); ImGui::SameLine();
|
|
ImGui::SetCursorPos(ImVec2(30, h - ImGui::GetTextLineHeightWithSpacing() - 4));
|
|
|
|
|
|
ImGui::PushFont(win.get_monofont());
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, regular_blue);
|
|
ImGui::PushItemWidth( w - get_dashboard_width() - 30 );
|
|
|
|
bool force_refresh = false;
|
|
if (ImGui::IsWindowFocused() && (ImGui::IsKeyPressed(GLFW_KEY_UP) || ImGui::IsKeyPressed(GLFW_KEY_DOWN)))
|
|
{
|
|
if (commands_histroy.size())
|
|
{
|
|
if (ImGui::IsKeyPressed(GLFW_KEY_UP)) history_offset = (history_offset + 1) % commands_histroy.size();
|
|
if (ImGui::IsKeyPressed(GLFW_KEY_DOWN)) history_offset = (history_offset - 1 + (int)commands_histroy.size()) % commands_histroy.size();
|
|
command_line = commands_histroy[history_offset];
|
|
|
|
force_refresh = true;
|
|
}
|
|
}
|
|
|
|
if (ImGui::IsWindowFocused() && ImGui::IsKeyPressed(GLFW_KEY_TAB))
|
|
{
|
|
if (!autocomplete.size() || !starts_with(to_lower(autocomplete.front()), to_lower(command_line)))
|
|
{
|
|
std::string commands_xml = config_file::instance().get(configurations::viewer::commands_xml);
|
|
std::ifstream f(commands_xml.c_str());
|
|
if (f.good())
|
|
{
|
|
std::string str((std::istreambuf_iterator<char>(f)),
|
|
std::istreambuf_iterator<char>());
|
|
|
|
autocomplete.clear();
|
|
std::regex exp("Command Name=\"(\\w+)\"");
|
|
std::smatch res;
|
|
std::string::const_iterator searchStart(str.cbegin());
|
|
while (regex_search(searchStart, str.cend(), res, exp))
|
|
{
|
|
if (starts_with(to_lower(res[1]), to_lower(command_line)))
|
|
autocomplete.push_back(res[1]);
|
|
searchStart = res.suffix().first;
|
|
}
|
|
}
|
|
}
|
|
if (autocomplete.size())
|
|
{
|
|
auto temp = autocomplete.front();
|
|
autocomplete.pop_front();
|
|
autocomplete.push_back(temp);
|
|
|
|
if (starts_with(to_lower(temp), command_line))
|
|
command_line = to_lower(autocomplete.front());
|
|
else
|
|
command_line = autocomplete.front();
|
|
force_refresh = true;
|
|
}
|
|
}
|
|
|
|
memcpy(buff, command_line.c_str(), command_line.size());
|
|
buff[command_line.size()] = 0;
|
|
|
|
int flags = ImGuiInputTextFlags_EnterReturnsTrue;
|
|
if (force_refresh)
|
|
{
|
|
flags = ImGuiInputTextFlags_ReadOnly;
|
|
}
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, scrollbar_bg);
|
|
if (ImGui::InputText("##TerminalCommand", buff, 1023, flags))
|
|
{
|
|
|
|
}
|
|
if (!command_focus && !new_log) command_line = buff;
|
|
ImGui::PopStyleColor();
|
|
if (command_focus || new_log) ImGui::SetKeyboardFocusHere();
|
|
ImGui::PopFont();
|
|
ImGui::PopStyleColor();
|
|
|
|
if (ImGui::IsWindowFocused() && (ImGui::IsKeyPressed(GLFW_KEY_ENTER) || ImGui::IsKeyPressed(GLFW_KEY_KP_ENTER)))
|
|
{
|
|
if (commands_histroy.size() > 100) commands_histroy.pop_back();
|
|
commands_histroy.push_front(command_line);
|
|
run_command(command_line, device_models);
|
|
command_line = "";
|
|
command_focus = true;
|
|
}
|
|
else command_focus = false;
|
|
|
|
if (ImGui::IsWindowFocused() && ImGui::IsKeyPressed(GLFW_KEY_ESCAPE))
|
|
{
|
|
command_line = "";
|
|
}
|
|
|
|
float child_height = 0;
|
|
for( auto && dash : dashboards )
|
|
{
|
|
child_height += dash->get_height();
|
|
}
|
|
float new_dashboard_button_height = 40.f;
|
|
child_height == 0 ? child_height = new_dashboard_button_height : child_height += 5;
|
|
|
|
auto dashboard_width = get_dashboard_width();
|
|
ImGui::SetCursorPos( ImVec2( w - dashboard_width, 35 ) );
|
|
|
|
ImGui::BeginChild( "##StatsArea", ImVec2( dashboard_width - 3.f, h - 38 ), true );
|
|
|
|
const ImVec2 collapse_dashboard_button_size = { 28, 28 };
|
|
const int max_dashboard_width = (int)( ( 0.3f * w ) );
|
|
const int min_dashboard_width = static_cast<int>(collapse_dashboard_button_size.x) + 2;
|
|
|
|
if( is_dashboard_open )
|
|
{
|
|
if( ImGui::Button( u8"\uf138", collapse_dashboard_button_size ) ) // close dashboard
|
|
{
|
|
is_dashboard_open = false;
|
|
config_file::instance().set( configurations::viewer::dashboard_open, is_dashboard_open );
|
|
default_dashboard_w = min_dashboard_width;
|
|
}
|
|
if( ImGui::IsItemHovered() )
|
|
{
|
|
ImGui::SetTooltip( "Collapse dashboard" );
|
|
}
|
|
|
|
// Animation of opening dashboard panel
|
|
if( default_dashboard_w.value() != max_dashboard_width )
|
|
default_dashboard_w = max_dashboard_width;
|
|
}
|
|
else
|
|
{
|
|
float cursor_pos_x = ImGui::GetCursorPosX();
|
|
ImGui::SetCursorPosX( 0 );
|
|
|
|
if( ImGui::Button( u8"\uf137", collapse_dashboard_button_size ) ) // open dashboard
|
|
{
|
|
is_dashboard_open = true;
|
|
config_file::instance().set( configurations::viewer::dashboard_open, is_dashboard_open );
|
|
default_dashboard_w = max_dashboard_width;
|
|
}
|
|
if( ImGui::IsItemHovered() )
|
|
{
|
|
ImGui::SetTooltip( "Open dashboard" );
|
|
}
|
|
ImGui::SetCursorPosX( cursor_pos_x );
|
|
|
|
// Animation of closing dashboard panel
|
|
if( default_dashboard_w.value() != min_dashboard_width )
|
|
default_dashboard_w = min_dashboard_width;
|
|
}
|
|
|
|
auto top = 0;
|
|
if( is_dashboard_open && dashboard_width == max_dashboard_width )
|
|
{
|
|
for( auto && dash : dashboards )
|
|
{
|
|
auto h = dash->get_height();
|
|
auto r = rect{ 0.f, (float)top, get_dashboard_width() - 8.f, (float)h };
|
|
dash->draw( win, r );
|
|
top += h;
|
|
}
|
|
}
|
|
|
|
dashboards.erase(std::remove_if(dashboards.begin(), dashboards.end(),
|
|
[](std::shared_ptr<stream_dashboard> p){
|
|
return p->closing();
|
|
}), dashboards.end());
|
|
|
|
bool can_add = false;
|
|
for (auto&& kvp : available_dashboards)
|
|
{
|
|
auto name = kvp.first;
|
|
auto it = std::find_if(dashboards.begin(), dashboards.end(),
|
|
[name](std::shared_ptr<stream_dashboard> p){
|
|
return p->get_name() == name;
|
|
});
|
|
if (it == dashboards.end()) can_add = true;
|
|
}
|
|
|
|
if (can_add)
|
|
{
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
|
const auto new_dashboard_name = "new_dashboard";
|
|
ImGui::SameLine();
|
|
if (ImGui::Button(u8"\uF0D0 Add Dashboard", ImVec2(-1, 25)))
|
|
{
|
|
ImGui::OpenPopup(new_dashboard_name);
|
|
}
|
|
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
ImGui::SetTooltip("Add one of the available stream dashboards to view");
|
|
win.link_hovered();
|
|
}
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, almost_white_bg);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, black);
|
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, light_blue);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(5,5));
|
|
if (ImGui::BeginPopup(new_dashboard_name))
|
|
{
|
|
for (auto&& kvp : available_dashboards)
|
|
{
|
|
auto name = kvp.first;
|
|
auto it = std::find_if(dashboards.begin(), dashboards.end(),
|
|
[name](std::shared_ptr<stream_dashboard> p){
|
|
return p->get_name() == name;
|
|
});
|
|
if (it == dashboards.end())
|
|
{
|
|
name = name + "##New";
|
|
bool selected = false;
|
|
if (ImGui::Selectable(name.c_str(), &selected))
|
|
{
|
|
dashboards.push_back(kvp.second(kvp.first));
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
ImGui::PopStyleColor(4);
|
|
ImGui::PopStyleVar();
|
|
}
|
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::PopStyleColor();
|
|
}
|
|
else foreach_log([&](log_entry& log) {});
|
|
|
|
|
|
ImGui::End();
|
|
ImGui::PopStyleColor(7);
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopFont();
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(devices_mutex);
|
|
this->devices.clear();
|
|
for (auto && dev_model : device_models)
|
|
this->devices.push_back(dev_model->dev);
|
|
}
|
|
}
|
|
|
|
void output_model::foreach_log(std::function<void(log_entry& line)> action)
|
|
{
|
|
std::lock_guard<std::recursive_mutex> lock(m);
|
|
|
|
// Process only the messages that are available upon invocation
|
|
log_entry le;
|
|
for (size_t len = 0; len < incoming_log_queue.size(); len++)
|
|
{
|
|
if (incoming_log_queue.try_dequeue(&le))
|
|
{
|
|
if (le.severity >= RS2_LOG_SEVERITY_ERROR) number_of_errors++;
|
|
else if (le.severity >= RS2_LOG_SEVERITY_WARN) number_of_warnings++;
|
|
else number_of_info++;
|
|
|
|
notification_logs.push_back(le);
|
|
}
|
|
}
|
|
|
|
// Limit the notification window
|
|
while (notification_logs.size() > 1000)
|
|
{
|
|
auto&& le = notification_logs.front();
|
|
if (le.severity >= RS2_LOG_SEVERITY_ERROR) number_of_errors--;
|
|
else if (le.severity >= RS2_LOG_SEVERITY_WARN) number_of_warnings--;
|
|
else number_of_info--;
|
|
notification_logs.pop_front();
|
|
}
|
|
|
|
for (auto&& l : notification_logs)
|
|
action(l);
|
|
|
|
if (new_log)
|
|
{
|
|
ImGui::SetScrollPosHere();
|
|
new_log = false;
|
|
}
|
|
}
|
|
|
|
// Callback function must not include mutex
|
|
void output_model::add_log(rs2_log_severity severity, std::string filename, int line_number, std::string line)
|
|
{
|
|
if (!line.size()) return;
|
|
|
|
time_t rawtime;
|
|
struct tm * timeinfo;
|
|
char buffer[80];
|
|
time (&rawtime);
|
|
timeinfo = localtime(&rawtime);
|
|
strftime(buffer,sizeof(buffer),"%H:%M:%S",timeinfo);
|
|
|
|
log_entry e;
|
|
e.line = line;
|
|
e.line_number = line_number;
|
|
e.filename = filename;
|
|
e.severity = severity;
|
|
e.timestamp = buffer;
|
|
e.time_added = glfwGetTime();
|
|
|
|
incoming_log_queue.enqueue(std::move(e));
|
|
new_log = true;
|
|
}
|
|
|
|
void output_model::run_command(std::string command, device_models_list & device_models)
|
|
{
|
|
try
|
|
{
|
|
if (to_lower(command) == "clear")
|
|
{
|
|
while (notification_logs.size() > 0)
|
|
{
|
|
auto&& le = notification_logs.front();
|
|
if (le.severity >= RS2_LOG_SEVERITY_ERROR) number_of_errors--;
|
|
else if (le.severity >= RS2_LOG_SEVERITY_WARN) number_of_warnings--;
|
|
else number_of_info--;
|
|
notification_logs.pop_front();
|
|
for (auto& d : dashboards)
|
|
d->clear(true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if( user_defined_command( command, device_models ) )
|
|
return;
|
|
|
|
std::regex e( "([0-9A-Fa-f]{2}\\s)+" );
|
|
|
|
if (std::regex_match(command, e))
|
|
{
|
|
add_log(RS2_LOG_SEVERITY_INFO, __FILE__, 0, rsutils::string::from() << "Trying to send " << command << "...");
|
|
|
|
std::vector<uint8_t> raw_data;
|
|
std::stringstream ss(command);
|
|
std::string word;
|
|
while (ss >> word)
|
|
{
|
|
std::stringstream converter;
|
|
int temp;
|
|
converter << std::hex << word;
|
|
converter >> temp;
|
|
raw_data.push_back(temp);
|
|
}
|
|
if (raw_data.empty())
|
|
throw std::runtime_error("Invalid input!");
|
|
|
|
bool found = false;
|
|
for (auto&& dev : devices)
|
|
{
|
|
if (auto dbg = dev.as<rs2::debug_protocol>())
|
|
{
|
|
found = true;
|
|
auto res = dbg.send_and_receive_raw_data(raw_data);
|
|
|
|
std::stringstream ss;
|
|
int i = 0;
|
|
for (auto& elem : res)
|
|
{
|
|
ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(elem) << " ";
|
|
i++;
|
|
if (i > 80)
|
|
{
|
|
ss << "\n";
|
|
i = 0;
|
|
}
|
|
}
|
|
add_log(RS2_LOG_SEVERITY_INFO, __FILE__, 0, ss.str());
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
add_log(RS2_LOG_SEVERITY_WARN, __FILE__, __LINE__, "No device is available to receive the command");
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::string commands_xml = config_file::instance().get(configurations::viewer::commands_xml);
|
|
std::ifstream f(commands_xml.c_str());
|
|
if (f.good())
|
|
{
|
|
std::string str((std::istreambuf_iterator<char>(f)),
|
|
std::istreambuf_iterator<char>());
|
|
auto terminal_parser = rs2::terminal_parser(str);
|
|
|
|
auto buffer = terminal_parser.parse_command(to_lower(command));
|
|
|
|
std::stringstream ss; ss << command << " = ";
|
|
for (auto& elem : buffer)
|
|
ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(elem) << " ";
|
|
|
|
add_log(RS2_LOG_SEVERITY_INFO, __FILE__, 0, ss.str());
|
|
|
|
bool found = false;
|
|
for (auto&& dev : devices)
|
|
{
|
|
if (auto dbg = dev.as<rs2::debug_protocol>())
|
|
{
|
|
found = true;
|
|
auto res = dbg.send_and_receive_raw_data(buffer);
|
|
|
|
std::string response = rsutils::string::from() << "\n" << terminal_parser.parse_response(to_lower(command), res);
|
|
add_log(RS2_LOG_SEVERITY_INFO, __FILE__, 0, response);
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
add_log(RS2_LOG_SEVERITY_WARN, __FILE__, __LINE__, "No device is available to receive the command");
|
|
|
|
return;
|
|
}
|
|
|
|
add_log(RS2_LOG_SEVERITY_WARN, __FILE__, __LINE__, rsutils::string::from() << "Unrecognized command '" << command << "'");
|
|
}
|
|
catch(const std::exception& ex)
|
|
{
|
|
add_log( RS2_LOG_SEVERITY_ERROR, __FILE__, __LINE__, ex.what() );
|
|
}
|
|
}
|
|
|
|
bool output_model::user_defined_command( std::string command, device_models_list & device_models )
|
|
{
|
|
bool user_defined_command_detected = false;
|
|
bool user_defined_command_activated = false;
|
|
|
|
// If a known command is detected , it will treated as a user_defined_command and will not be
|
|
// passed to the FW commands check logic.
|
|
// Note: For now we find the first device that supports the command and activate the command only on it.
|
|
|
|
if( to_lower( command ) == "get-nest" )
|
|
{
|
|
user_defined_command_detected = true;
|
|
|
|
for( auto && dev : devices )
|
|
{
|
|
if( auto dbg = dev.as< rs2::debug_protocol >() )
|
|
{
|
|
// Verify minimal version for handling this command
|
|
std::vector< uint8_t > special_command
|
|
= { 'G', 'E', 'T', '-', 'N', 'E', 'S', 'T' };
|
|
auto res = dbg.send_and_receive_raw_data( special_command );
|
|
user_defined_command_activated = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Log a warning if a known command was not activated
|
|
if( user_defined_command_detected && ! user_defined_command_activated )
|
|
{
|
|
add_log( RS2_LOG_SEVERITY_WARN,
|
|
__FILE__,
|
|
__LINE__,
|
|
rsutils::string::from() << "None of the connected devices supports '" << command << "'" );
|
|
}
|
|
|
|
return user_defined_command_detected;
|
|
}
|
|
|
|
|
|
void output_model::update_dashboards(rs2::frame f)
|
|
{
|
|
for (auto&& d : dashboards)
|
|
d->add_frame(f);
|
|
}
|
|
|
|
void stream_dashboard::draw_dashboard(ux_window& win, rect& r)
|
|
{
|
|
auto min_x = 0.f;
|
|
auto max_x = 1.f;
|
|
auto min_y = 0.f;
|
|
auto max_y = 1.f;
|
|
|
|
if (xy.size())
|
|
{
|
|
min_x = xy[0].first;
|
|
max_x = xy[0].first;
|
|
min_y = xy[0].second;
|
|
max_y = xy[0].second;
|
|
for (auto&& p : xy)
|
|
{
|
|
min_x = std::min(min_x, p.first);
|
|
min_y = std::min(min_y, p.second);
|
|
max_x = std::max(max_x, p.first);
|
|
max_y = std::max(max_y, p.second);
|
|
}
|
|
}
|
|
|
|
auto gap_y = max_y - min_y;
|
|
auto gap_x = max_x - min_x;
|
|
auto height_y = r.h - 2 * ImGui::GetTextLineHeight() - 10;
|
|
auto ticks_y = ceil(height_y / ImGui::GetTextLineHeight());
|
|
|
|
auto max_y_label_width = 0.f;
|
|
for (int i = 0; i <= ticks_y; i++)
|
|
{
|
|
auto y = max_y - i * (gap_y / ticks_y);
|
|
std::string y_label = rsutils::string::from() << std::fixed << std::setprecision(2) << y;
|
|
auto size = ImGui::CalcTextSize(y_label.c_str());
|
|
max_y_label_width = std::max(max_y_label_width,
|
|
size.x);
|
|
}
|
|
|
|
auto pos = ImGui::GetCursorScreenPos();
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Text, white);
|
|
|
|
ImGui::GetWindowDrawList()->AddRectFilled({ pos.x, pos.y },
|
|
{ pos.x + r.w - 1, pos.y + get_height() - 1 }, ImColor(header_color));
|
|
ImGui::GetWindowDrawList()->AddRect({ pos.x, pos.y },
|
|
{ pos.x + r.w, pos.y + get_height() }, ImColor(dark_sensor_bg));
|
|
|
|
auto size = ImGui::CalcTextSize(name.c_str());
|
|
float collapse_buton_h = 28.f + 3.f; // Dashboard button size plus some spacing
|
|
ImGui::SetCursorPos(ImVec2( r.w / 2 - size.x / 2, 5 + collapse_buton_h));
|
|
ImGui::Text("%s", name.c_str());
|
|
ImGui::SameLine();
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Text, grey);
|
|
ImGui::SetCursorPosX(r.w - 25);
|
|
ImGui::SetCursorPosY( 3.f + collapse_buton_h );
|
|
std::string id = rsutils::string::from() << u8"\uF00D##Close_" << name;
|
|
if (ImGui::Button(id.c_str(),ImVec2(22,22)))
|
|
{
|
|
close();
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
ImGui::SetTooltip("Remove Dashboard from View");
|
|
win.link_hovered();
|
|
}
|
|
ImGui::PopStyleColor();
|
|
|
|
ImGui::GetWindowDrawList()->AddRectFilled({ pos.x + max_y_label_width + 15, pos.y + ImGui::GetTextLineHeight() + 5 },
|
|
{ pos.x + r.w - 10, pos.y + r.h - ImGui::GetTextLineHeight() - 5 }, ImColor(almost_white_bg));
|
|
|
|
//ImGui::PushFont(win.get_monofont());
|
|
for (int i = 0; i <= ticks_y; i++)
|
|
{
|
|
auto y = max_y - i * (gap_y / ticks_y);
|
|
std::string y_label = rsutils::string::from() << std::fixed << std::setprecision(2) << y;
|
|
auto y_pixel = ImGui::GetTextLineHeight() + i * (height_y / ticks_y);
|
|
ImGui::SetCursorPos(ImVec2( 10, y_pixel + collapse_buton_h));
|
|
ImGui::Text("%s", y_label.c_str());
|
|
|
|
ImGui::GetWindowDrawList()->AddLine({ pos.x + max_y_label_width + 15.f, pos.y + y_pixel + 5.f },
|
|
{ pos.x + r.w - 10.f, pos.y + y_pixel + 5.f }, ImColor(light_grey));
|
|
}
|
|
|
|
auto graph_width = r.w - max_y_label_width - 25;
|
|
|
|
int ticks_x = 2;
|
|
bool has_room = true;
|
|
while (has_room)
|
|
{
|
|
float total = 0;
|
|
for (int i = 0; i <= ticks_x; i++)
|
|
{
|
|
auto x = min_x + i * (gap_x / ticks_x);
|
|
std::string x_label = rsutils::string::from() << std::fixed << std::setprecision(2) << x;
|
|
auto size = ImGui::CalcTextSize(x_label.c_str());
|
|
total += size.x;
|
|
}
|
|
if (total < graph_width) ticks_x++;
|
|
else has_room = false;
|
|
}
|
|
ticks_x -= 3;
|
|
|
|
for (int i = 0; i < ticks_x; i++)
|
|
{
|
|
auto x = min_x + i * (gap_x / ticks_x);
|
|
std::string x_label = rsutils::string::from() << std::fixed << std::setprecision(2) << x;
|
|
ImGui::SetCursorPos(ImVec2( 15 + max_y_label_width+ i * (graph_width / ticks_x), r.h - ImGui::GetTextLineHeight() + collapse_buton_h));
|
|
ImGui::Text("%s", x_label.c_str());
|
|
|
|
ImGui::GetWindowDrawList()->AddLine({ pos.x + 15 + max_y_label_width + i * (graph_width / ticks_x), pos.y + ImGui::GetTextLineHeight() + 5 },
|
|
{ pos.x + max_y_label_width + 15 + i * (graph_width / ticks_x), pos.y + ImGui::GetTextLineHeight() + 5 + height_y }, ImColor(light_grey));
|
|
}
|
|
|
|
std::sort(xy.begin(), xy.end(), [](const std::pair<float, float>& a, const std::pair<float, float>& b) { return a.first < b.first; });
|
|
|
|
for (int i = 0; i + 1 < xy.size(); i++)
|
|
{
|
|
auto x0 = xy[i].first;
|
|
auto y0 = xy[i].second;
|
|
|
|
auto x1 = xy[i+1].first;
|
|
auto y1 = xy[i+1].second;
|
|
|
|
x0 = (x0 - min_x) / (max_x - min_x);
|
|
x1 = (x1 - min_x) / (max_x - min_x);
|
|
|
|
y0 = (y0 - min_y) / (max_y - min_y);
|
|
y1 = (y1 - min_y) / (max_y - min_y);
|
|
|
|
ImGui::GetWindowDrawList()->AddLine({ pos.x + 15 + max_y_label_width + x0 * graph_width, pos.y + ImGui::GetTextLineHeight() + 5 + height_y * (1.f - y0) },
|
|
{ pos.x + 15 + max_y_label_width + x1 * graph_width, pos.y + ImGui::GetTextLineHeight() + 5 + height_y * (1.f - y1) }, ImColor(black));
|
|
}
|
|
|
|
//ImGui::PopFont();
|
|
ImGui::PopStyleColor();
|
|
|
|
xy.clear();
|
|
}
|
|
|
|
void frame_drops_dashboard::process_frame(rs2::frame f)
|
|
{
|
|
write_shared_data([&](){
|
|
double ts = glfwGetTime();
|
|
if (method == 1) ts = f.get_timestamp() / 1000.f;
|
|
auto it = stream_to_time.find(f.get_profile().unique_id());
|
|
if (it != stream_to_time.end())
|
|
{
|
|
auto last = stream_to_time[f.get_profile().unique_id()];
|
|
|
|
double fps = (double)f.get_profile().fps();
|
|
|
|
if( f.supports_frame_metadata( RS2_FRAME_METADATA_ACTUAL_FPS ) )
|
|
fps = f.get_frame_metadata( RS2_FRAME_METADATA_ACTUAL_FPS ) / 1000.;
|
|
|
|
if (1000. * (ts - last) > 1.5 * (1000. / fps)) {
|
|
drops++;
|
|
}
|
|
}
|
|
|
|
counter++;
|
|
|
|
if (ts - last_time > 1.f)
|
|
{
|
|
if (drops_history.size() > 100) drops_history.pop_front();
|
|
drops_history.push_back(drops);
|
|
*total = counter;
|
|
*frame_drop_count = drops;
|
|
drops = 0;
|
|
last_time = ts;
|
|
counter = 0;
|
|
}
|
|
|
|
stream_to_time[f.get_profile().unique_id()] = ts;
|
|
});
|
|
}
|
|
|
|
void frame_drops_dashboard::draw(ux_window& win, rect r)
|
|
{
|
|
auto hist = read_shared_data<std::deque<int>>([&](){ return drops_history; });
|
|
for (int i = 0; i < hist.size(); i++)
|
|
{
|
|
add_point((float)i, (float)hist[i]);
|
|
}
|
|
r.h -= ImGui::GetTextLineHeightWithSpacing() + 10;
|
|
|
|
if( config_file::instance().get( configurations::viewer::dashboard_open) )
|
|
draw_dashboard(win, r);
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 40);
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 3);
|
|
ImGui::Text("%s", "Measurement Metric:"); ImGui::SameLine();
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 3);
|
|
|
|
ImGui::SetCursorPosX( 11.5f * win.get_font_size() );
|
|
|
|
std::vector<const char*> methods;
|
|
methods.push_back("Viewer Processing Rate");
|
|
methods.push_back("Camera Timestamp Rate");
|
|
|
|
ImGui::PushItemWidth(-1.f);
|
|
if (ImGui::Combo("##fps_method", &method, methods.data(), (int)(methods.size())))
|
|
{
|
|
clear(false);
|
|
}
|
|
ImGui::PopItemWidth();
|
|
}
|
|
|
|
int frame_drops_dashboard::get_height() const
|
|
{
|
|
return (int)(160 + ImGui::GetTextLineHeightWithSpacing());
|
|
}
|
|
|
|
void frame_drops_dashboard::clear(bool full)
|
|
{
|
|
write_shared_data([&](){
|
|
stream_to_time.clear();
|
|
last_time = 0;
|
|
*total = 0;
|
|
*frame_drop_count = 0;
|
|
if (full)
|
|
{
|
|
drops_history.clear();
|
|
for (int i = 0; i < 100; i++)
|
|
drops_history.push_back(0);
|
|
}
|
|
});
|
|
}
|