156 lines
5.6 KiB
C++
156 lines
5.6 KiB
C++
#include "tools/cabana/ui/chart/signalselector.h"
|
|
|
|
#include <algorithm>
|
|
#include <cfloat>
|
|
|
|
#include "imgui.h"
|
|
#include "tools/cabana/streams/abstractstream.h"
|
|
#include "tools/cabana/ui/chart/chart.h"
|
|
#include "tools/cabana/ui/icons.h"
|
|
#include "tools/cabana/ui/util.h"
|
|
#include "tools/cabana/utils/strings.h"
|
|
|
|
SignalSelector::SignalSelector(std::string title) : title_(std::move(title)) {
|
|
for (const auto &[id, _] : can->lastMessages()) {
|
|
if (auto m = dbc()->msg(id)) {
|
|
msgs_combo_.push_back({m->name + " (" + id.toString() + ")", id});
|
|
}
|
|
}
|
|
std::sort(msgs_combo_.begin(), msgs_combo_.end(), [](auto &a, auto &b) { return a.text < b.text; });
|
|
}
|
|
|
|
bool SignalSelector::draw() {
|
|
if (!open_) return false;
|
|
const std::string popup_id = title_ + "###SignalSelector";
|
|
if (!show_) {
|
|
ImGui::OpenPopup(popup_id.c_str());
|
|
show_ = true;
|
|
}
|
|
setNextDialogWindow(ImVec2(700.0f, 450.0f));
|
|
if (!ImGui::BeginPopupModal(popup_id.c_str(), nullptr, ImGuiWindowFlags_NoSavedSettings)) {
|
|
open_ = false;
|
|
return false;
|
|
}
|
|
|
|
const float btn_w = ImGui::GetFrameHeight() + 8.0f;
|
|
const float column_w = (ImGui::GetContentRegionAvail().x - btn_w - ImGui::GetStyle().ItemSpacing.x * 2) / 2;
|
|
|
|
const float lists_h = ImGui::GetContentRegionAvail().y - ImGui::GetFrameHeightWithSpacing() * 3;
|
|
|
|
ImGui::BeginGroup();
|
|
ImGui::TextUnformatted("Available Signals");
|
|
|
|
const char *preview = msgs_combo_index_ >= 0 ? msgs_combo_[msgs_combo_index_].text.c_str() : "Select a msg...";
|
|
ImGui::SetNextItemWidth(column_w);
|
|
if (ImGui::BeginCombo("##msgs_combo", preview)) {
|
|
if (ImGui::IsWindowAppearing()) {
|
|
msgs_combo_filter_.clear();
|
|
ImGui::SetKeyboardFocusHere();
|
|
}
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
inputText("##msgs_filter", &msgs_combo_filter_, "Select a msg...");
|
|
for (int i = 0; i < (int)msgs_combo_.size(); ++i) {
|
|
if (!msgs_combo_filter_.empty() && !utils::containsCI(msgs_combo_[i].text, msgs_combo_filter_)) continue;
|
|
if (ImGui::Selectable(msgs_combo_[i].text.c_str(), i == msgs_combo_index_)) {
|
|
msgs_combo_index_ = i;
|
|
updateAvailableList(i);
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
}
|
|
ImGui::EndCombo();
|
|
}
|
|
bool add_dbl = false;
|
|
drawList("##available_list", available_list_, &available_row_, false, &add_dbl, ImVec2(column_w, lists_h));
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::SameLine();
|
|
ImGui::BeginGroup();
|
|
ImGui::Dummy(ImVec2(btn_w, (lists_h + ImGui::GetFrameHeightWithSpacing() * 2) / 2 - ImGui::GetFrameHeight()));
|
|
ImGui::BeginDisabled(available_row_ == -1);
|
|
bool add_clicked = ImGui::Button(icon::CHEVRON_RIGHT, ImVec2(btn_w, 0));
|
|
ImGui::EndDisabled();
|
|
ImGui::BeginDisabled(selected_row_ == -1);
|
|
bool remove_clicked = ImGui::Button(icon::CHEVRON_LEFT, ImVec2(btn_w, 0));
|
|
ImGui::EndDisabled();
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::SameLine();
|
|
ImGui::BeginGroup();
|
|
ImGui::TextUnformatted("Selected Signals");
|
|
bool remove_dbl = false;
|
|
drawList("##selected_list", selected_list_, &selected_row_, true, &remove_dbl, ImVec2(column_w, lists_h + ImGui::GetFrameHeightWithSpacing()));
|
|
bool rejected = false;
|
|
dialogButtons("OK", &accepted_, &rejected);
|
|
const bool done = accepted_ || rejected;
|
|
ImGui::EndGroup();
|
|
|
|
if ((add_dbl || add_clicked) && available_row_ >= 0 && available_row_ < (int)available_list_.size()) {
|
|
add(available_row_);
|
|
} else if ((remove_dbl || remove_clicked) && selected_row_ >= 0 && selected_row_ < (int)selected_list_.size()) {
|
|
remove(selected_row_);
|
|
}
|
|
|
|
if (done) {
|
|
open_ = false;
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::EndPopup();
|
|
return open_;
|
|
}
|
|
|
|
void SignalSelector::drawList(const char *id, std::vector<ListItem> &list, int *current_row, bool show_msg_name, bool *double_clicked, const ImVec2 &size) {
|
|
if (!ImGui::BeginListBox(id, size)) return;
|
|
for (int i = 0; i < (int)list.size(); ++i) {
|
|
const auto &item = list[i];
|
|
ImGui::PushID(i);
|
|
const ImVec2 pos = ImGui::GetCursorScreenPos();
|
|
if (ImGui::Selectable("##item", i == *current_row)) *current_row = i;
|
|
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
|
*current_row = i;
|
|
*double_clicked = true;
|
|
}
|
|
|
|
ImDrawList *dl = ImGui::GetWindowDrawList();
|
|
float x = pos.x + 5;
|
|
drawColorMarker(dl, ImVec2(x, pos.y), toImU32(item.sig->color));
|
|
x += markerSize() + 4;
|
|
dl->AddText(ImVec2(x, pos.y), ImGui::GetColorU32(ImGuiCol_Text), item.sig->name.c_str());
|
|
if (show_msg_name) {
|
|
x += ImGui::CalcTextSize(item.sig->name.c_str()).x;
|
|
dl->AddText(ImVec2(x, pos.y), ImGui::GetColorU32(ImGuiCol_TextDisabled), msgLabel(item.msg_id).c_str());
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
ImGui::EndListBox();
|
|
}
|
|
|
|
void SignalSelector::add(int row) {
|
|
const auto &item = available_list_[row];
|
|
selected_list_.emplace_back(item.msg_id, item.sig);
|
|
available_list_.erase(available_list_.begin() + row);
|
|
available_row_ = -1;
|
|
}
|
|
|
|
void SignalSelector::remove(int row) {
|
|
const auto &item = selected_list_[row];
|
|
if (msgs_combo_index_ >= 0 && item.msg_id == msgs_combo_[msgs_combo_index_].id) {
|
|
available_list_.emplace_back(item.msg_id, item.sig);
|
|
}
|
|
selected_list_.erase(selected_list_.begin() + row);
|
|
selected_row_ = -1;
|
|
}
|
|
|
|
void SignalSelector::updateAvailableList(int index) {
|
|
if (index == -1) return;
|
|
available_list_.clear();
|
|
available_row_ = -1;
|
|
MessageId msg_id = msgs_combo_[index].id;
|
|
for (auto s : dbc()->msg(msg_id)->getSignals()) {
|
|
bool is_selected = std::any_of(selected_list_.begin(), selected_list_.end(),
|
|
[sig = s, &msg_id](auto &it) { return it.msg_id == msg_id && it.sig == sig; });
|
|
if (!is_selected) {
|
|
available_list_.emplace_back(msg_id, s);
|
|
}
|
|
}
|
|
}
|