10int MsgBox::next_id_counter_ = 1;
17 , id_counter_(next_id_counter_++)
19 , animation_progress_(0.0f)
20 , custom_icon_(nullptr)
22 CalculateButtonLayout();
29 callback_ = std::move(callback);
31 animation_start_ = std::chrono::steady_clock::now();
32 animation_progress_ = 0.0f;
33 open_requested_ =
true;
46 float alpha = GetAnimationAlpha();
47 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
50 if (config_.center_on_screen)
52 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
53 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, {0.5f, 0.5f});
57 if (config_.background_color.w > 0.0f)
59 ImGui::PushStyleColor(ImGuiCol_PopupBg, config_.background_color);
63 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {20, 20});
64 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f);
65 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {12, 8});
68 ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings;
69 if (!config_.allow_resize)
71 flags |= ImGuiWindowFlags_NoResize;
73 if (!config_.show_close_button)
75 flags |= ImGuiWindowFlags_NoTitleBar;
80 std::string window_title = config_.show_close_button ?
81 (title_ +
"###MsgBox" + std::to_string(id_counter_)) :
82 (
"###MsgBox" + std::to_string(id_counter_));
86 ImGui::OpenPopup(window_title.c_str());
87 open_requested_ =
false;
90 if (ImGui::BeginPopupModal(window_title.c_str(), &is_open, flags))
93 ImVec2 window_size = ImGui::GetWindowSize();
94 if (window_size.x < config_.min_size.x || window_size.y < config_.min_size.y ||
95 window_size.x > config_.max_size.x || window_size.y > config_.max_size.y)
98 std::max(config_.min_size.x, std::min(config_.max_size.x, window_size.x)),
99 std::max(config_.min_size.y, std::min(config_.max_size.y, window_size.y))
101 ImGui::SetWindowSize(new_size);
121 animation_start_ = std::chrono::steady_clock::now();
129 ImGui::PopStyleVar(3);
131 if (config_.background_color.w > 0.0f)
133 ImGui::PopStyleColor();
136 ImGui::PopStyleVar();
141auto MsgBox::CalculateButtonLayout() ->
void
143 button_layout_.clear();
146 std::vector<std::pair<ModalResult, std::string>> button_definitions = {
167 for (
const auto& [result, label] : button_definitions)
169 if (buttons_ & result)
171 button_layout_.push_back({result, label});
176auto MsgBox::DrawIcon() ->
void
178 const char*
icon = custom_icon_ ? custom_icon_ : GetTypeIcon();
181 ImVec4 icon_color = GetTypeColor();
182 ImGui::PushStyleColor(ImGuiCol_Text, icon_color);
186 ImGui::Text(
"%s",
icon);
189 ImGui::PopStyleColor();
192auto MsgBox::DrawMessage() ->
void
197 if (!config_.show_close_button && !title_.empty())
199 ImGui::Text(
"%s", title_.c_str());
204 float available_width = std::min(config_.max_size.x - 100.0f, 400.0f);
205 ImGui::PushTextWrapPos(ImGui::GetCursorPos().
x + available_width);
206 ImGui::TextWrapped(
"%s", message_.c_str());
207 ImGui::PopTextWrapPos();
212auto MsgBox::DrawButtons() ->
void
214 if (button_layout_.empty())
return;
216 const float button_width = 100.0f;
217 const float button_height = 30.0f;
218 const float spacing = ImGui::GetStyle().ItemSpacing.x;
221 float total_width = button_layout_.size() * button_width + (button_layout_.size() - 1) * spacing;
222 float available_width = ImGui::GetContentRegionAvail().x;
225 if (total_width < available_width)
227 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (available_width - total_width) * 0.5f);
231 for (
size_t i = 0;
i < button_layout_.size(); ++
i)
233 const auto& [result, label] = button_layout_[
i];
235 if (i > 0) ImGui::SameLine();
238 if (i == 0 && ImGui::IsWindowAppearing())
240 ImGui::SetKeyboardFocusHere();
251 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.6f, 0.2f, 1.0f));
252 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.7f, 0.3f, 1.0f));
253 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.1f, 0.5f, 0.1f, 1.0f));
255 else if (is_destructive)
257 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.6f, 0.2f, 0.2f, 1.0f));
258 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.7f, 0.3f, 0.3f, 1.0f));
259 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.5f, 0.1f, 0.1f, 1.0f));
262 bool clicked = ImGui::Button(label.c_str(), {button_width, button_height});
264 if (is_primary || is_destructive)
266 ImGui::PopStyleColor(3);
273 animation_start_ = std::chrono::steady_clock::now();
293 animation_start_ = std::chrono::steady_clock::now();
302auto MsgBox::UpdateAnimation() ->
void
309 auto now = std::chrono::steady_clock::now();
310 float elapsed = std::chrono::duration<float>(now - animation_start_).count();
311 animation_progress_ = std::min(1.0f,
elapsed / config_.animation_duration);
313 if (animation_progress_ >= 1.0f)
322 ImGui::CloseCurrentPopup();
327auto MsgBox::GetTypeIcon() const -> const
char*
329 switch (config_.
type)
341auto MsgBox::GetTypeColor() const -> ImVec4
343 switch (config_.
type)
351 default:
return ImVec4(0.3f, 0.7f, 1.0f, 1.0f);
355auto MsgBox::GetAnimationAlpha() const ->
float
368 float t = animation_progress_;
369 return t *
t * (3.0f - 2.0f *
t);
374 float t = 1.0f - animation_progress_;
375 return t *
t * (3.0f - 2.0f *
t);
390 const std::string& title,
391 const std::string& message,
394 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
396 auto message_box = std::make_shared<MsgBox>(title, message, buttons, config);
397 message_box->OpenPopup(callback);
398 active_boxes_.push_back(message_box);
404 CleanupClosedBoxes();
407 for (
auto it = active_boxes_.rbegin(); it != active_boxes_.rend(); ++it)
416 active_boxes_.clear();
419auto MsgBoxManager::CleanupClosedBoxes() ->
void
422 std::remove_if(active_boxes_.begin(), active_boxes_.end(),
423 [](
const std::shared_ptr<MsgBox>& box) {
424 return !box || !box->IsOpen();
426 active_boxes_.end());
431auto ShowInfo(
const std::string& title,
const std::string& message,
432 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
439auto ShowWarning(
const std::string& title,
const std::string& message,
440 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
447auto ShowError(
const std::string& title,
const std::string& message,
448 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
455auto ShowSuccess(
const std::string& title,
const std::string& message,
456 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
464 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
473 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
482 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>
492 std::function<
void(
ModalResult)> callback) -> std::shared_ptr<MsgBox>