270 lines
10 KiB
C++
270 lines
10 KiB
C++
#include <imgui/imgui.h>
|
|
#include <imgui/misc/cpp/imgui_stdlib.h>
|
|
|
|
#include "../misc.h"
|
|
#include "../group_panel.h"
|
|
#include "../filters.h"
|
|
#include "ok_buttons_fragment.h"
|
|
#include "filters.h"
|
|
|
|
static inline void render_integer_filter(IntegerFilter* filter);
|
|
static inline void render_string_filter(StringFilter* filter);
|
|
static inline void render_buffer_filter(BufferFilter* filter);
|
|
static inline void render_priority_filter(PriorityFilter* filter);
|
|
static inline void render_group_filter(GroupFilter* filter);
|
|
static std::unique_ptr<Filter> render_add_filter_popup();
|
|
|
|
static void render_filter(Filter* filter, std::string* title, bool* request_removal,
|
|
auto move_up, auto move_down, bool can_move_up, bool can_move_down) {
|
|
ImGui::PushID(filter);
|
|
ImGui::BeginGroupPanel();
|
|
|
|
if (title) {
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::Text("Title:%s%s", title->empty() ? "" : " ", title->c_str());
|
|
ImGui::SameLine();
|
|
|
|
bool popup_just_opened = false;
|
|
if (ImGui::Button("Edit")) {
|
|
ImGui::OpenPopup("change_filter_title");
|
|
popup_just_opened = true;
|
|
}
|
|
if (ImGui::BeginPopup("change_filter_title")) {
|
|
ImGui::SetKeyboardFocusHere();
|
|
bool enter_pressed = ImGui::InputText("##title", title, ImGuiInputTextFlags_EnterReturnsTrue);
|
|
if (enter_pressed || (!popup_just_opened && !ImGui::IsItemActive())) {
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::EndPopup();
|
|
}
|
|
ImGui::SameLine();
|
|
}
|
|
|
|
if (ImGui::Button("Remove")) {
|
|
*request_removal = true;
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
if (ImGui::ArrowButton("##up", ImGuiDir_Up, can_move_up)) {
|
|
move_up();
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::ArrowButton("##down", ImGuiDir_Down, can_move_down)) {
|
|
move_down();
|
|
}
|
|
|
|
{
|
|
ImGui::SameLine();
|
|
bool disabled = filter->disabled();
|
|
if (ImGui::Checkbox("Disabled", &disabled)) {
|
|
filter->disabled(disabled);
|
|
}
|
|
}
|
|
|
|
{
|
|
StringFilter* sfilter = dynamic_cast<StringFilter*>(filter);
|
|
IntegerFilter* ifilter = !sfilter ? dynamic_cast<IntegerFilter*>(filter) : nullptr;
|
|
if (sfilter || ifilter) {
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox("Inverted", sfilter ? &sfilter->inverted : &ifilter->inverted);
|
|
}
|
|
if (sfilter) {
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox("Exact match", &sfilter->exact_match);
|
|
}
|
|
}
|
|
|
|
if (filter->error()) {
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::Text("(%s)", filter->error()->c_str());
|
|
}
|
|
|
|
if (IntegerFilter* ifilter = dynamic_cast<IntegerFilter*>(filter)) {
|
|
render_integer_filter(ifilter);
|
|
} else if (StringFilter* sfilter = dynamic_cast<StringFilter*>(filter)) {
|
|
render_string_filter(sfilter);
|
|
} else if (BufferFilter* bfilter = dynamic_cast<BufferFilter*>(filter)) {
|
|
render_buffer_filter(bfilter);
|
|
} else if (PriorityFilter* pfilter = dynamic_cast<PriorityFilter*>(filter)) {
|
|
render_priority_filter(pfilter);
|
|
} else if (GroupFilter* gfilter = dynamic_cast<GroupFilter*>(filter)) {
|
|
render_group_filter(gfilter);
|
|
} else {
|
|
ImGui::TextUnformatted("An unknown filter, this probably shouldn't be mutated");
|
|
}
|
|
|
|
ImGui::EndGroupPanel();
|
|
ImGui::PopID();
|
|
}
|
|
|
|
static inline void render_integer_filter(IntegerFilter* filter) {
|
|
const char* head;
|
|
switch (filter->key) {
|
|
case FilterKey::PID: head = "PID"; break;
|
|
case FilterKey::TID: head = "TID"; break;
|
|
default: head = "Something";
|
|
};
|
|
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::Text("%s is%s:", head, filter->inverted ? " not" : "");
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
if (ImGui::InputScalar("##int", ImGuiDataType_U64, &filter->other)) {
|
|
filter->updated();
|
|
}
|
|
}
|
|
|
|
static inline void render_string_filter(StringFilter* filter) {
|
|
const char* head;
|
|
switch (filter->key) {
|
|
case FilterKey::User: head = "User"; break;
|
|
case FilterKey::Tag: head = "Tag"; break;
|
|
case FilterKey::Message: head = "Message"; break;
|
|
default: head = "Something";
|
|
};
|
|
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::Text("%s %s:", head, filter->exact_match
|
|
? (filter->inverted ? "is not" : "is")
|
|
: (filter->inverted ? "doesn't have" : "has"));
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
if (ImGui::InputText("##str", &filter->other)) {
|
|
filter->updated();
|
|
}
|
|
}
|
|
|
|
static inline void render_buffer_filter(BufferFilter* filter) {
|
|
auto add_checkbox = [&](const char* name, Buffer buffer) {
|
|
if (ImGui::CheckboxFlags(name, &filter->wanted, static_cast<unsigned int>(buffer))) {
|
|
filter->updated();
|
|
}
|
|
};
|
|
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::TextUnformatted("Buffer is:"); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
add_checkbox("Unknown", Buffer::Unknown); ImGui::SameLine();
|
|
add_checkbox("Main", Buffer::Main); ImGui::SameLine();
|
|
add_checkbox("System", Buffer::System); ImGui::SameLine();
|
|
add_checkbox("Radio", Buffer::Radio); ImGui::SameLine();
|
|
add_checkbox("Events", Buffer::Events); ImGui::SameLine();
|
|
add_checkbox("Crash", Buffer::Crash);
|
|
}
|
|
|
|
static inline void render_priority_filter(PriorityFilter* filter) {
|
|
auto add_checkbox = [&](const char* name, Priority priority) {
|
|
if (ImGui::CheckboxFlags(name, &filter->wanted, static_cast<unsigned int>(priority))) {
|
|
filter->updated();
|
|
}
|
|
};
|
|
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::TextUnformatted("Priority is:"); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
add_checkbox("Unknown", Priority::Unknown); ImGui::SameLine();
|
|
add_checkbox("Verbose", Priority::Verbose); ImGui::SameLine();
|
|
add_checkbox("Debug", Priority::Debug); ImGui::SameLine();
|
|
add_checkbox("Info", Priority::Info); ImGui::SameLine();
|
|
add_checkbox("Warning", Priority::Warn); ImGui::SameLine();
|
|
add_checkbox("Error", Priority::Error); ImGui::SameLine();
|
|
add_checkbox("Fatal", Priority::Fatal);
|
|
}
|
|
|
|
static inline void render_group_filter(GroupFilter* filter) {
|
|
int selected_type = static_cast<int>(filter->type);
|
|
if (ImGui::Combo("of these are true", &selected_type, "All\0Any\0One\0None\0")) {
|
|
filter->type = static_cast<GroupFilter::Type>(selected_type);
|
|
}
|
|
|
|
std::vector<std::pair<size_t, size_t>> swaps_to_do;
|
|
std::vector<size_t> removals_to_do;
|
|
for (size_t i = 0; i < filter->filters.size(); i++) {
|
|
bool removal_requested = false;
|
|
render_filter(filter->filters[i].get(), nullptr, &removal_requested, [&]() {
|
|
swaps_to_do.push_back(std::make_pair(i, i - 1));
|
|
}, [&]() {
|
|
swaps_to_do.push_back(std::make_pair(i, i + 1));
|
|
}, i != 0, i + 1 != filter->filters.size());
|
|
|
|
if (removal_requested) {
|
|
removals_to_do.push_back(i);
|
|
}
|
|
}
|
|
for (auto &[lhs, rhs] : swaps_to_do) {
|
|
std::swap(filter->filters[lhs], filter->filters[rhs]);
|
|
filter->updated();
|
|
}
|
|
for (size_t i : removals_to_do) {
|
|
filter->filters.erase(filter->filters.begin() + static_cast<ssize_t>(i));
|
|
filter->updated();
|
|
}
|
|
|
|
if (ImGui::Button("+ add filter")) {
|
|
ImGui::OpenPopup("add_filter");
|
|
}
|
|
if (ImGui::BeginPopup("add_filter")) {
|
|
std::unique_ptr<Filter> added_filter = render_add_filter_popup();
|
|
if (added_filter) {
|
|
filter->filters.push_back(std::move(added_filter));
|
|
filter->updated();
|
|
}
|
|
ImGui::EndPopup();
|
|
}
|
|
}
|
|
|
|
static std::unique_ptr<Filter> render_add_filter_popup() {
|
|
if (ImGui::Selectable("Buffer")) {
|
|
return std::make_unique<BufferFilter>(0, false);
|
|
} else if (ImGui::Selectable("User")) {
|
|
return std::make_unique<StringFilter>(FilterKey::User, "", false, true, false);
|
|
} else if (ImGui::Selectable("PID")) {
|
|
return std::make_unique<IntegerFilter>(FilterKey::PID, 0, false, false);
|
|
} else if (ImGui::Selectable("TID")) {
|
|
return std::make_unique<IntegerFilter>(FilterKey::TID, 0, false, false);
|
|
} else if (ImGui::Selectable("Priority")) {
|
|
return std::make_unique<PriorityFilter>(0, false);
|
|
} else if (ImGui::Selectable("Tag")) {
|
|
return std::make_unique<StringFilter>(FilterKey::Tag, "", false, true, false);
|
|
} else if (ImGui::Selectable("Message")) {
|
|
return std::make_unique<StringFilter>(FilterKey::Message, "", false, true, false);
|
|
} else if (ImGui::Selectable("Group of filters")) {
|
|
return std::make_unique<GroupFilter>(std::vector<std::unique_ptr<Filter>>(), GroupFilter::Type::All, false);
|
|
}
|
|
|
|
return std::unique_ptr<Filter>();
|
|
}
|
|
|
|
void filters_fragment(Filters& inactive_filters) {
|
|
ImGui::TextWrapped("You can use regex for strings by prepending \"regex:\". "
|
|
"While editing titles, press Enter to use the new title or press Escape to keep the old one");
|
|
|
|
std::vector<std::pair<size_t, size_t>> swaps_to_do;
|
|
std::vector<size_t> removals_to_do;
|
|
for (size_t i = 0; i < inactive_filters.size(); i++) {
|
|
bool removal_requested = false;
|
|
render_filter(inactive_filters[i].second.get(), &inactive_filters[i].first, &removal_requested, [&]() {
|
|
swaps_to_do.push_back(std::make_pair(i, i - 1));
|
|
}, [&]() {
|
|
swaps_to_do.push_back(std::make_pair(i, i + 1));
|
|
}, i != 0, i + 1 != inactive_filters.size());
|
|
|
|
if (removal_requested) {
|
|
removals_to_do.push_back(i);
|
|
}
|
|
}
|
|
for (auto &[lhs, rhs] : swaps_to_do) {
|
|
std::swap(inactive_filters[lhs], inactive_filters[rhs]);
|
|
}
|
|
for (size_t i : removals_to_do) {
|
|
inactive_filters.erase(inactive_filters.begin() + static_cast<ssize_t>(i));
|
|
}
|
|
|
|
if (ImGui::Button("+ add filter")) {
|
|
ImGui::OpenPopup("add_filter");
|
|
}
|
|
if (ImGui::BeginPopup("add_filter")) {
|
|
std::unique_ptr<Filter> added_filter = render_add_filter_popup();
|
|
if (added_filter) {
|
|
inactive_filters.push_back(std::make_pair("", std::move(added_filter)));
|
|
}
|
|
ImGui::EndPopup();
|
|
}
|
|
}
|