-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is there a header which uses C++ lifetimes to guard part of the api? #6963
Comments
Much appreciated, thank you. Edit: In the process of waiting for answer I decided to write my own, not sure this is complete for all of imgui's apis, but it seems complete for "imgui.h" (There may be bugs in here). #pragma once
#include "imgui.h"
namespace ImGuiGaurd {
struct DeferEnd {
bool result;
operator bool() {
return result;
}
~DeferEnd() {
ImGui::End();
}
};
[[nodiscard]] DeferEnd Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0) {
return DeferEnd{ ImGui::Begin(name, p_open, flags) };
};
struct DeferEndChild {
bool result;
operator bool() {
return result;
}
~DeferEndChild() {
ImGui::End();
}
};
[[nodiscard]] DeferEndChild BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0) {
return DeferEndChild{ ImGui::BeginChild(str_id, size, border, flags) };
};
[[nodiscard]] DeferEndChild BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0) {
return DeferEndChild{ ImGui::BeginChild(id, size, border, flags) };
};
struct DeferEndGroup {
~DeferEndGroup() {
ImGui::EndGroup();
}
};
[[nodiscard]] DeferEndGroup BeginGroup() {
ImGui::BeginGroup();
return DeferEndGroup{};
};
struct DeferEndCombo {
bool result;
operator bool() {
return result;
}
~DeferEndCombo() {
if (result)
ImGui::EndCombo();
}
};
DeferEndCombo BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0) {
return DeferEndCombo{ ImGui::BeginCombo(label, preview_value, flags) };
};
DeferEndCombo Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1) {
return DeferEndCombo{ ImGui::Combo(label, current_item, items, items_count, popup_max_height_in_items) };
};
DeferEndCombo Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1) {
return DeferEndCombo{ ImGui::Combo(label, current_item, items_separated_by_zeros, popup_max_height_in_items) };
};
DeferEndCombo Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1) {
return DeferEndCombo{ ImGui::Combo(label, current_item, items_getter, data, items_count, popup_max_height_in_items) };
};
struct DeferEndListBox {
bool result;
operator bool() {
return result;
}
~DeferEndListBox() {
if (result)
ImGui::EndListBox();
}
};
DeferEndListBox BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)) {
return DeferEndListBox{ ImGui::BeginListBox(label, size) };
};
DeferEndListBox ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1) {
return DeferEndListBox{ ImGui::ListBox(label, current_item, items, items_count, height_in_items) };
};
DeferEndListBox ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1) {
return DeferEndListBox{ ImGui::ListBox(label, current_item, items_getter, data, items_count, height_in_items) };
};
struct DeferEndMenuBar {
bool result;
operator bool() {
return result;
}
~DeferEndMenuBar() {
if (result)
ImGui::EndMenuBar();
}
};
DeferEndMenuBar BeginMenuBar() {
return DeferEndMenuBar{ ImGui::BeginMenuBar() };
};
struct DeferEndMainMenuBar {
bool result;
operator bool() {
return result;
}
~DeferEndMainMenuBar() {
if (result)
ImGui::EndMainMenuBar();
}
};
DeferEndMainMenuBar BeginMainMenuBar() {
return DeferEndMainMenuBar{ ImGui::BeginMainMenuBar() };
};
struct DeferEndMenu {
bool result;
operator bool() {
return result;
}
~DeferEndMenu() {
if (result)
ImGui::EndMenu();
}
};
DeferEndMenu BeginMenu(const char* label, bool enabled = true) {
return DeferEndMenu{ ImGui::BeginMenu(label, enabled) };
};
struct DeferEndTooltip {
~DeferEndTooltip() {
ImGui::EndTooltip();
}
};
DeferEndTooltip BeginTooltip() {
ImGui::BeginTooltip();
return DeferEndTooltip{};
};
struct DeferEndPopup {
bool result;
operator bool() {
return result;
}
~DeferEndPopup() {
if (result)
ImGui::EndPopup();
}
};
DeferEndPopup BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0) {
return DeferEndPopup{ ImGui::BeginPopup(str_id, flags) };
};
DeferEndPopup BeginPopupModal(const char* str_id, bool* p_open, ImGuiWindowFlags flags = 0) {
return DeferEndPopup{ ImGui::BeginPopupModal(str_id, p_open, flags) };
};
struct DeferEndTable {
bool result;
operator bool() {
return result;
}
~DeferEndTable() {
if (result)
ImGui::EndTable();
}
};
DeferEndTable BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f) {
return DeferEndTable{ ImGui::BeginTable(str_id, column, flags, outer_size, inner_width) };
};
struct DeferEndTabBar {
bool result;
operator bool() {
return result;
}
~DeferEndTabBar() {
if (result)
ImGui::EndTabBar();
}
};
DeferEndTabBar BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0) {
return DeferEndTabBar{ ImGui::BeginTabBar(str_id, flags) };
};
struct DeferEndTabItem {
bool result;
operator bool() {
return result;
}
~DeferEndTabItem() {
if (result)
ImGui::EndTabItem();
}
};
DeferEndTabItem BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0) {
return DeferEndTabItem{ ImGui::BeginTabItem(label, p_open, flags) };
};
struct DeferEndDragDropSource {
bool result;
operator bool() {
return result;
}
~DeferEndDragDropSource() {
if (result)
ImGui::EndDragDropSource();
}
};
DeferEndDragDropSource BeginDragDropSource(ImGuiDragDropFlags flags = 0) {
return DeferEndDragDropSource{ ImGui::BeginDragDropSource(flags) };
};
struct DeferEndDragDropTarget {
bool result;
operator bool() {
return result;
}
~DeferEndDragDropTarget() {
if (result)
ImGui::EndDragDropTarget();
}
};
DeferEndDragDropTarget BeginDragDropTarget() {
return DeferEndDragDropTarget{ ImGui::BeginDragDropTarget() };
};
struct DeferEndDisabled {
~DeferEndDisabled() {
ImGui::EndDisabled();
}
};
DeferEndDisabled BeginDisabled(bool disabled = true) {
return DeferEndDisabled{};
};
struct DeferEndChildFrame {
bool result;
operator bool() {
return result;
}
~DeferEndChildFrame() {
ImGui::EndChildFrame();
}
};
DeferEndChildFrame BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0) {
return DeferEndChildFrame{ ImGui::BeginChildFrame(id, size, flags) };
};
} |
Combo() and ListBox() are not BeginXXX functions so don’t need this. Traditionally my reluctance with this that Push/Pop functions may be interleaved in asymmetrical manners with other functions, and that adopting this style tends to prevents it. Your idiom may only be safely used if the user opens a scope for every begin/end, not doing so may lead to undesired behavior. |
Yeah I've already run into an issue that without upping the warning level |
My Issue/Question:
A lot of the api uses begin / end paired functions, in fact a lot of these functions do additional asserts to make sure that to some degree that these stay in some amount of sync.
I'm curious if there's a header or project which might've wrapped these function calls to provide a struct which calls the appropriate destructor. Think the trick used to defer a lambda function to the end of a function call.
So for example the api might look like:
The only slight concern I have if this doesn't exist already would be the parts of the api which don't require a paired "End" call which may make things confusing.
The text was updated successfully, but these errors were encountered: