SDRPlusPlus/core/src/gui/widgets/menu.cpp

218 wiersze
7.8 KiB
C++
Czysty Zwykły widok Historia

#include <gui/widgets/menu.h>
#include <imgui/imgui.h>
2020-12-08 03:36:37 +00:00
#include <imgui/imgui_internal.h>
2021-07-09 02:29:16 +00:00
#include <gui/style.h>
2020-09-19 22:19:39 +00:00
Menu::Menu() {
}
2020-12-08 03:36:37 +00:00
void Menu::registerEntry(std::string name, void (*drawHandler)(void* ctx), void* ctx, ModuleManager::Instance* inst) {
2020-09-19 22:19:39 +00:00
MenuItem_t item;
item.drawHandler = drawHandler;
item.ctx = ctx;
2020-12-08 03:36:37 +00:00
item.inst = inst;
2020-09-19 22:19:39 +00:00
items[name] = item;
2020-09-24 17:36:57 +00:00
if (!isInOrderList(name)) {
2021-04-22 21:49:35 +00:00
MenuOption_t opt;
opt.name = name;
opt.open = true;
order.push_back(opt);
2020-09-24 17:36:57 +00:00
}
2020-09-19 22:19:39 +00:00
}
void Menu::removeEntry(std::string name) {
items.erase(name);
}
2021-04-23 01:58:10 +00:00
bool Menu::draw(bool updateStates) {
2021-04-22 21:49:35 +00:00
bool changed = false;
2020-12-08 03:36:37 +00:00
float menuWidth = ImGui::GetContentRegionAvailWidth();
ImGuiWindow* window = ImGui::GetCurrentWindow();
ImVec2 checkboxOffset = ImVec2(menuWidth - ImGui::GetTextLineHeight() - (6.0f * style::uiScale), - ImGui::GetTextLineHeight() - (10.0f * style::uiScale));
2021-07-09 02:29:16 +00:00
2021-07-10 16:33:11 +00:00
int displayedCount = 0;
2021-07-09 15:55:17 +00:00
int rawId = 0;
2021-07-09 02:29:16 +00:00
ImU32 textColor = ImGui::GetColorU32(ImGuiCol_Text);
2021-04-22 21:49:35 +00:00
for (MenuOption_t& opt : order) {
2021-07-09 15:55:17 +00:00
rawId++;
2021-04-22 21:49:35 +00:00
if (items.find(opt.name) == items.end()) {
2020-09-24 17:36:57 +00:00
continue;
}
2021-07-09 02:29:16 +00:00
if (opt.name == draggedMenuName) {
ImGui::BeginTooltip();
ImGui::Text("%s", draggedMenuName.c_str());
ImGui::EndTooltip();
continue;
}
// Draw dragged menu item
2021-07-10 16:33:11 +00:00
if (displayedCount == insertBefore && !draggedMenuName.empty()) {
2021-07-09 02:29:16 +00:00
if (updateStates) { ImGui::SetNextItemOpen(false); }
ImVec2 posMin = ImGui::GetCursorScreenPos();
ImVec2 posMax = ImVec2(posMin.x + menuWidth, posMin.y + ImGui::GetFrameHeight());
style::beginDisabled();
2021-07-09 15:55:17 +00:00
ImRect orignalRect = window->WorkRect;
2021-07-09 02:29:16 +00:00
ImGui::CollapsingHeader((draggedMenuName + "##sdrpp_main_menu_dragging").c_str());
2021-07-09 15:55:17 +00:00
if (items[draggedOpt.name].inst != NULL) {
window->WorkRect = orignalRect;
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosX(pos.x + checkboxOffset.x);
ImGui::SetCursorPosY(pos.y + checkboxOffset.y);
2021-07-09 15:55:17 +00:00
bool enabled = items[draggedOpt.name].inst->isEnabled();
ImGui::Checkbox(("##_menu_checkbox_" + draggedOpt.name).c_str(), &enabled);
ImGui::SetCursorPos(pos);
}
2021-07-09 02:29:16 +00:00
style::endDisabled();
window->DrawList->AddRect(posMin, posMax, textColor, 0.0f, 0, style::uiScale);
2021-07-09 02:29:16 +00:00
}
2021-07-10 16:33:11 +00:00
displayedCount++;
2021-04-22 21:49:35 +00:00
MenuItem_t& item = items[opt.name];
2020-12-08 03:36:37 +00:00
ImRect orginalRect = window->WorkRect;
if (item.inst != NULL) {
window->WorkRect = ImRect(orginalRect.Min, ImVec2(orginalRect.Max.x - ImGui::GetTextLineHeight() - (6.0f * style::uiScale), orginalRect.Max.y));
2020-12-08 03:36:37 +00:00
}
2021-07-09 02:29:16 +00:00
ImVec2 posMin = ImGui::GetCursorScreenPos();
ImVec2 posMax = ImVec2(posMin.x + menuWidth, posMin.y + ImGui::GetFrameHeight());
headerTops[displayedCount - 1] = posMin.y;
optionIDs[displayedCount - 1] = rawId - 1;
2021-07-09 02:29:16 +00:00
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsMouseHoveringRect(posMin, posMax)) {
menuClicked = true;
clickedMenuName = opt.name;
}
2021-07-10 16:33:11 +00:00
if (menuClicked && ImGui::IsMouseDragging(ImGuiMouseButton_Left) && draggedMenuName.empty() && clickedMenuName == opt.name) {
2021-07-09 02:29:16 +00:00
draggedMenuName = opt.name;
draggedId = rawId - 1;
2021-07-09 15:55:17 +00:00
draggedOpt = opt;
2021-07-09 02:29:16 +00:00
continue;
}
// Draw menu header and menu content. There is a lot of boilerplate because the checkbox has to be drawn before the menu, TODO: fix
2021-04-23 01:58:10 +00:00
if (updateStates) { ImGui::SetNextItemOpen(opt.open); }
if (ImGui::CollapsingHeader((opt.name + "##sdrpp_main_menu").c_str())) {
2020-12-08 03:36:37 +00:00
if (item.inst != NULL) {
window->WorkRect = orginalRect;
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosX(pos.x + checkboxOffset.x);
ImGui::SetCursorPosY(pos.y + checkboxOffset.y);
2020-12-08 03:36:37 +00:00
bool enabled = item.inst->isEnabled();
2021-04-22 21:49:35 +00:00
if (ImGui::Checkbox(("##_menu_checkbox_" + opt.name).c_str(), &enabled)) {
2020-12-08 03:36:37 +00:00
enabled ? item.inst->enable() : item.inst->disable();
changed = true;
2020-12-08 03:36:37 +00:00
}
ImGui::SetCursorPos(pos);
}
2021-04-22 21:49:35 +00:00
// Check if the state changed
2021-04-23 01:58:10 +00:00
if (!opt.open && !updateStates) {
2021-04-22 21:49:35 +00:00
opt.open = true;
changed = true;
}
2020-09-24 17:36:57 +00:00
item.drawHandler(item.ctx);
ImGui::Spacing();
2020-09-24 17:36:57 +00:00
}
2020-12-08 03:36:37 +00:00
else if (item.inst != NULL) {
window->WorkRect = orginalRect;
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosX(pos.x + checkboxOffset.x);
ImGui::SetCursorPosY(pos.y + checkboxOffset.y);
2020-12-08 03:36:37 +00:00
bool enabled = item.inst->isEnabled();
2021-04-22 21:49:35 +00:00
if (ImGui::Checkbox(("##_menu_checkbox_" + opt.name).c_str(), &enabled)) {
2020-12-08 03:36:37 +00:00
enabled ? item.inst->enable() : item.inst->disable();
changed = true;
2020-12-08 03:36:37 +00:00
}
ImGui::SetCursorPos(pos);
2021-04-22 21:49:35 +00:00
2021-04-23 01:58:10 +00:00
if (opt.open && !updateStates) {
2021-04-22 21:49:35 +00:00
opt.open = false;
changed = true;
}
}
2021-04-23 01:58:10 +00:00
else if (opt.open && !updateStates) {
2021-04-22 21:49:35 +00:00
opt.open = false;
changed = true;
2020-12-08 03:36:37 +00:00
}
2020-09-24 17:36:57 +00:00
}
2021-07-09 02:29:16 +00:00
if (!ImGui::IsMouseDown(ImGuiMouseButton_Left) && menuClicked) {
2021-07-10 16:33:11 +00:00
if (!draggedMenuName.empty()) {
2021-07-09 02:29:16 +00:00
// Move menu
2021-07-09 15:55:17 +00:00
order.erase(order.begin() + draggedId);
2021-07-09 02:29:16 +00:00
2021-07-10 16:33:11 +00:00
if (insertBefore == displayedCount) {
2021-07-09 15:55:17 +00:00
order.push_back(draggedOpt);
2021-07-09 02:29:16 +00:00
}
else if (insertBeforeName != "") {
int beforeId = 0;
for (int i = 0; i < order.size(); i++) {
if (order[i].name == insertBeforeName) {
beforeId = i;
break;
}
}
2021-07-09 15:55:17 +00:00
order.insert(order.begin() + beforeId, draggedOpt);
2021-07-09 02:29:16 +00:00
}
changed = true;
}
2021-07-09 02:29:16 +00:00
menuClicked = false;
draggedMenuName = "";
insertBeforeName = "";
insertBefore = -1;
}
// TODO: Figure out why the hell this is needed
2021-07-10 16:33:11 +00:00
if (insertBefore == displayedCount && !draggedMenuName.empty()) {
2021-07-09 02:29:16 +00:00
if (updateStates) { ImGui::SetNextItemOpen(false); }
ImVec2 posMin = ImGui::GetCursorScreenPos();
ImVec2 posMax = ImVec2(posMin.x + menuWidth, posMin.y + ImGui::GetFrameHeight());
style::beginDisabled();
2021-07-09 15:55:17 +00:00
ImRect orignalRect = window->WorkRect;
2021-07-09 02:29:16 +00:00
ImGui::CollapsingHeader((draggedMenuName + "##sdrpp_main_menu_dragging").c_str());
2021-07-09 15:55:17 +00:00
if (items[draggedOpt.name].inst != NULL) {
window->WorkRect = orignalRect;
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosX(pos.x + checkboxOffset.x);
ImGui::SetCursorPosY(pos.y + checkboxOffset.y);
2021-07-09 15:55:17 +00:00
bool enabled = items[draggedOpt.name].inst->isEnabled();
ImGui::Checkbox(("##_menu_checkbox_" + draggedOpt.name).c_str(), &enabled);
ImGui::SetCursorPos(pos);
}
2021-07-09 02:29:16 +00:00
style::endDisabled();
window->DrawList->AddRect(posMin, posMax, textColor, 0.0f, 0, style::uiScale);
2021-07-09 02:29:16 +00:00
}
2021-07-10 16:33:11 +00:00
if (!draggedMenuName.empty()) {
insertBefore = displayedCount;
2021-07-09 02:29:16 +00:00
ImVec2 mPos = ImGui::GetMousePos();
2021-07-10 16:33:11 +00:00
for (int i = 0; i < displayedCount; i++) {
2021-07-09 02:29:16 +00:00
if (headerTops[i] > mPos.y) {
insertBefore = i;
2021-07-10 16:33:11 +00:00
insertBeforeName = order[optionIDs[i]].name;
2021-07-09 02:29:16 +00:00
break;
}
}
}
2021-04-22 21:49:35 +00:00
return changed;
2020-09-24 17:36:57 +00:00
}
bool Menu::isInOrderList(std::string name) {
2021-04-22 21:49:35 +00:00
for (MenuOption_t opt : order) {
if (opt.name == name) {
2020-09-24 17:36:57 +00:00
return true;
}
2020-09-19 22:19:39 +00:00
}
2020-09-24 17:36:57 +00:00
return false;
2020-09-19 22:19:39 +00:00
}