diff options
author | rtk0c <[email protected]> | 2021-03-31 20:19:18 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-03-31 20:19:18 -0700 |
commit | 44f5fa5c8f258e8fc1f7d7e2e45e0485bd6cc490 (patch) | |
tree | 3f09a1cce46d38f5a8c6266150e67af3802d4b95 /core/src/UI | |
parent | 31950890c939862f79c817053c106bf711c63a64 (diff) |
Complete items tab (UI and serialization)
Diffstat (limited to 'core/src/UI')
-rw-r--r-- | core/src/UI/Localization.hpp | 32 | ||||
-rw-r--r-- | core/src/UI/States.cpp | 4 | ||||
-rw-r--r-- | core/src/UI/States.hpp | 1 | ||||
-rw-r--r-- | core/src/UI/UI.hpp | 9 | ||||
-rw-r--r-- | core/src/UI/UI_Items.cpp | 212 | ||||
-rw-r--r-- | core/src/UI/UI_MainWindow.cpp | 102 | ||||
-rw-r--r-- | core/src/UI/UI_Utils.cpp | 38 |
7 files changed, 292 insertions, 106 deletions
diff --git a/core/src/UI/Localization.hpp b/core/src/UI/Localization.hpp index d5424ea..86b7afc 100644 --- a/core/src/UI/Localization.hpp +++ b/core/src/UI/Localization.hpp @@ -12,6 +12,7 @@ public: static std::unique_ptr<LocaleStrings> Instance; public: + BasicTranslation Error{ "Generic.Error"sv }; BasicTranslation DialogConfirm{ "Generic.Dialog.Confirm"sv }; BasicTranslation DialogCancel{ "Generic.Dialog.Cancel"sv }; @@ -26,8 +27,8 @@ public: BasicTranslation NewProjectNameHint{ "Project.New.Name"sv }; BasicTranslation NewProjectPathHint{ "Project.New.Path"sv }; BasicTranslation NewProjectPathDialogTitle{ "Project.New.Path.DialogTitle"sv }; - BasicTranslation NewProjectEmptyNameError{ "Project.New.EmptyName"sv }; - BasicTranslation NewProjectInvalidPathError{ "Project.New.InvalidPath"sv }; + BasicTranslation NewProjectEmptyNameError{ "Project.New.EmptyNameError"sv }; + BasicTranslation NewProjectInvalidPathError{ "Project.New.InvalidPathError"sv }; BasicTranslation OpenProject{ "Project.Open"sv }; BasicTranslation OpenProjectDialogTitle{ "Project.Open.DialogTitle"sv }; @@ -38,18 +39,29 @@ public: BasicTranslation OpenRecentProjectTooltip{ "Project.Recents.Open.Tooltip"sv }; BasicTranslation DeleteRecentProjectTooltip{ "Project.Recents.Delete.Tooltip"sv }; + BasicTranslation InvalidProjectFormat{ "Project.InvalidProjectFormat"sv }; + BasicTranslation CloseActiveProject{ "ActiveProject.Close"sv }; BasicTranslation OpenActiveProjectInFileSystem{ "ActiveProject.OpenInFilesystem"sv }; BasicTranslation ActiveProjectName{ "ActiveProject.Info.Name"sv }; BasicTranslation ActiveProjectPath{ "ActiveProject.Info.Path"sv }; - BasicTranslation AddItem{ "ItemEditor.Add"sv }; - BasicTranslation AddItemDialogTitle{ "ItemEditor.Add.DialogTitle"sv }; - BasicTranslation DeleteItem{ "ItemEditor.Delete"sv }; + BasicTranslation AddItem{ "Item.Add"sv }; + BasicTranslation AddItemDialogTitle{ "Item.Add.DialogTitle"sv }; + BasicTranslation EditItem{ "Item.Edit"sv }; + BasicTranslation EditItemDialogTitle{ "Item.Edit.DialogTitle"sv }; + BasicTranslation DeleteItem{ "Item.Delete"sv }; + BasicTranslation DeleteItemDialogTitle{ "Item.Delete.DialogTitle"sv }; + BasicTranslation DeleteItemDialogMessage{ "Item.Delete.DialogMessage"sv }; + + BasicTranslation ProductCategoryName{ "Item.CategoryName.Product"sv }; + BasicTranslation FactoryCategoryName{ "Item.CategoryName.Factory"sv }; + BasicTranslation CustomerCategoryName{ "Item.CategoryName.Customer"sv }; + + BasicTranslation ItemNameColumn{ "Item.Column.Name"sv }; + BasicTranslation ItemDescriptionColumn{ "Item.Column.Description"sv }; + BasicTranslation ItemEmailColumn{ "Item.Column.Email"sv }; - BasicTranslation ProductCategoryName{ "Item.Product.CategoryName"sv }; - BasicTranslation ProductNameColumn{ "Item.Product.Column.Name"sv }; - BasicTranslation ProductDescriptionColumn{ "Item.Product.Column.Description"sv }; - BasicTranslation FactoryCategoryName{ "Item.Factory.CategoryName"sv }; - BasicTranslation CustomerCategoryName{ "Item.Customer.CategoryName"sv }; + BasicTranslation EmptyItemNameError{ "Item.EmptyNameError"sv }; + BasicTranslation DuplicateItemNameError{ "Item.DuplicateNameError"sv }; }; diff --git a/core/src/UI/States.cpp b/core/src/UI/States.cpp index dc7c37a..546e1ab 100644 --- a/core/src/UI/States.cpp +++ b/core/src/UI/States.cpp @@ -1,5 +1,6 @@ #include "States.hpp" +#include "Model/GlobalStates.hpp" #include "Model/Project.hpp" #include <memory> @@ -24,6 +25,9 @@ UIState& UIState::GetInstance() { void UIState::SetCurrentProject(std::unique_ptr<Project> project) { CloseCurrentProject(); + if (project) { + GlobalStates::GetInstance().MoveProjectToTop(*project); + } CurrentProject = std::move(project); } diff --git a/core/src/UI/States.hpp b/core/src/UI/States.hpp index de0510c..4cc3b0f 100644 --- a/core/src/UI/States.hpp +++ b/core/src/UI/States.hpp @@ -3,6 +3,7 @@ #include "cplt_fwd.hpp" #include <memory> +#include <imgui.h> /// Minimal state shared by all UI components, such as database, items, export, etc. /// Note that global components (settings) is not supposed to access these. diff --git a/core/src/UI/UI.hpp b/core/src/UI/UI.hpp index 52a2ca9..ab35321 100644 --- a/core/src/UI/UI.hpp +++ b/core/src/UI/UI.hpp @@ -4,14 +4,19 @@ namespace ImGui { -void SetNextWindowSizeRelScreen(float xPercent, float yPercent, ImGuiCond_ cond = ImGuiCond_None); -void SetNextWindowCentered(ImGuiCond_ cond = ImGuiCond_None); +void SetNextWindowSizeRelScreen(float xPercent, float yPercent, ImGuiCond cond = ImGuiCond_None); +void SetNextWindowCentered(ImGuiCond cond = ImGuiCond_None); void PushDisabled(); void PopDisabled(); +bool Button(const char* label, bool disabled); +bool Button(const char* label, const ImVec2& sizeArg, bool disabled); + void ErrorIcon(); +void ErrorMessage(const char* fmt, ...); void WarningIcon(); +void WarningMessage(const char* fmt, ...); } // namespace ImGui diff --git a/core/src/UI/UI_Items.cpp b/core/src/UI/UI_Items.cpp index a990a96..970d0df 100644 --- a/core/src/UI/UI_Items.cpp +++ b/core/src/UI/UI_Items.cpp @@ -5,106 +5,202 @@ #include "UI/Localization.hpp" #include "UI/States.hpp" -#include <IconsFontAwesome.h> #include <imgui.h> #include <imgui_stdlib.h> namespace { -/// Specialized for each item type. -template <class T> -void AddToItemListDialog(ItemList<T>& list); -/// Specialized for each item type. -template <class T> -void ItemListEntries(ItemList<T>& list); -template <> -void AddToItemListDialog<ProductItem>(ItemList<ProductItem>& list) { - static std::string productName; - static std::string description; +enum class ActionResult { + Confirmed, + Canceled, + Pending, +}; + +/// \param list Item list that the item is in. +/// \param item A non-null pointer to the currently being edited item. It should not change until this function returns a non-\c ActionResult::Pending value. +template <class T> +ActionResult ItemEditor(ItemList<T>& list, T* item) { + constexpr bool kHasDescription = requires(T t) { t.GetDescription(); }; + constexpr bool kHasEmail = requires(T t) { t.GetEmail(); }; auto ls = LocaleStrings::Instance.get(); auto& uis = UIState::GetInstance(); - ImGui::InputText(ls->ProductNameColumn.Get(), &productName); - ImGui::InputText(ls->ProductDescriptionColumn.Get(), &description); - if (ImGui::Button(ls->DialogConfirm.Get())) { - auto& product = uis.CurrentProject->Products.Insert(std::move(productName)); - product.SetDescription(std::move(description)); + static bool duplicateName = false; + + static std::string name; + static std::string description; + static std::string email; + if (name.empty()) { + name = item->GetName(); + if constexpr (kHasDescription) description = item->GetDescription(); + if constexpr (kHasEmail) email = item->GetEmail(); + } + + auto ClearStates = [&]() { + duplicateName = false; + name = {}; + description = {}; + }; + + if (ImGui::InputText(ls->ItemNameColumn.Get(), &name)) { + duplicateName = name != item->GetName() && list.Find(name) != nullptr; + } + if constexpr (kHasDescription) ImGui::InputText(ls->ItemDescriptionColumn.Get(), &description); + if constexpr (kHasEmail) ImGui::InputText(ls->ItemEmailColumn.Get(), &email); + + if (name.empty()) { + ImGui::ErrorMessage("%s", ls->EmptyItemNameError.Get()); + } + if (duplicateName) { + ImGui::ErrorMessage("%s", ls->DuplicateItemNameError.Get()); + } + + // Return Value + auto rv = ActionResult::Pending; - productName.clear(); - description.clear(); + if (ImGui::Button(ls->DialogConfirm.Get(), name.empty() || duplicateName)) { + if (item->GetName() != name) { + item->SetName(std::move(name)); + } + if constexpr (kHasDescription) + if (item->GetDescription() != description) { + item->SetDescription(std::move(description)); + } + if constexpr (kHasEmail) + if (item->GetEmail() != email) { + item->SetEmail(std::move(email)); + } ImGui::CloseCurrentPopup(); + ClearStates(); + rv = ActionResult::Confirmed; } + ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { ImGui::CloseCurrentPopup(); + ClearStates(); + rv = ActionResult::Canceled; } -} -template <> -void AddToItemListDialog<FactoryItem>(ItemList<FactoryItem>& list) { - // TODO + return rv; } -template <> -void AddToItemListDialog<CustomerItem>(ItemList<CustomerItem>& list) { - // TODO -} +template <class T> +void ItemListEntries(ItemList<T>& list, int& selectedIdx) { + constexpr bool kHasDescription = requires(T t) { t.GetDescription(); }; + constexpr bool kHasEmail = requires(T t) { t.GetEmail(); }; + constexpr int kColumns = 1 /* Name column */ + kHasDescription + kHasEmail; -template <> -void ItemListEntries<ProductItem>(ItemList<ProductItem>& list) { auto ls = LocaleStrings::Instance.get(); - if (ImGui::BeginTable("ItemListEntries", 2)) { + auto& uis = UIState::GetInstance(); - ImGui::TableSetupColumn(ls->ProductNameColumn.Get()); - ImGui::TableSetupColumn(ls->ProductDescriptionColumn.Get()); + if (ImGui::BeginTable("", kColumns, ImGuiTableFlags_Borders)) { + + ImGui::TableSetupColumn(ls->ItemNameColumn.Get()); + if constexpr (kHasDescription) ImGui::TableSetupColumn(ls->ItemDescriptionColumn.Get()); + if constexpr (kHasEmail) ImGui::TableSetupColumn(ls->ItemEmailColumn.Get()); ImGui::TableHeadersRow(); + size_t idx = 0; for (auto& entry : list) { + if (entry.IsInvalid()) { + continue; + } + ImGui::TableNextRow(); + // Field: name ImGui::TableNextColumn(); - ImGui::Text("%s", entry.GetName().c_str()); - ImGui::TableNextColumn(); - ImGui::Text("%.8s", entry.GetDescription().c_str()); - if (ImGui::Button(ICON_FA_EDIT)) { - // TODO + if (ImGui::Selectable(entry.GetName().c_str(), selectedIdx == idx, ImGuiSelectableFlags_SpanAllColumns)) { + selectedIdx = idx; + } + + // Field: description + if constexpr (kHasDescription) { + ImGui::TableNextColumn(); + ImGui::Text("%s", entry.GetDescription().c_str()); + } + + // Field: email + if constexpr (kHasEmail) { + ImGui::TableNextColumn(); + ImGui::Text("%s", entry.GetEmail().c_str()); } + + idx++; } ImGui::EndTable(); } } -template <> -void ItemListEntries<FactoryItem>(ItemList<FactoryItem>& list) { - // TODO -} - -template <> -void ItemListEntries<CustomerItem>(ItemList<CustomerItem>& list) { - // TODO -} - template <class T> void ItemListEditor(ItemList<T>& list) { auto ls = LocaleStrings::Instance.get(); + bool opened = true; + static int selectedIdx = -1; + static T* editingItem = nullptr; + if (ImGui::Button(ls->AddItem.Get())) { ImGui::SetNextWindowCentered(); ImGui::OpenPopup(ls->AddItemDialogTitle.Get()); + + editingItem = &list.Insert(""); + } + if (ImGui::BeginPopupModal(ls->AddItemDialogTitle.Get(), &opened, ImGuiWindowFlags_AlwaysAutoResize)) { + switch (ItemEditor(list, editingItem)) { + case ActionResult::Confirmed: + editingItem = nullptr; + break; + case ActionResult::Canceled: + list.Remove(editingItem->GetId()); + editingItem = nullptr; + break; + default: + break; + } + ImGui::EndPopup(); + } + + ImGui::SameLine(); + if (ImGui::Button(ls->EditItem.Get(), selectedIdx == -1)) { + ImGui::SetNextWindowCentered(); + ImGui::OpenPopup(ls->EditItemDialogTitle.Get()); + + editingItem = list.Find(selectedIdx); } - if (ImGui::BeginPopupModal(ls->AddItemDialogTitle.Get())) { - AddToItemListDialog<T>(list); + if (ImGui::BeginPopupModal(ls->EditItemDialogTitle.Get(), &opened, ImGuiWindowFlags_AlwaysAutoResize)) { + if (ItemEditor(list, editingItem) != ActionResult::Pending) { + editingItem = nullptr; + } ImGui::EndPopup(); } ImGui::SameLine(); - if (ImGui::Button(ls->DeleteItem.Get())) { - // TODO + if (ImGui::Button(ls->DeleteItem.Get(), selectedIdx == -1)) { + ImGui::SetNextWindowCentered(); + ImGui::OpenPopup(ls->DeleteItemDialogTitle.Get()); + + list.Remove(selectedIdx); + } + if (ImGui::BeginPopupModal(ls->DeleteItemDialogTitle.Get(), &opened, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("%s", ls->DeleteItemDialogMessage.Get()); + + if (ImGui::Button(ls->DialogConfirm.Get())) { + ImGui::CloseCurrentPopup(); + } + + ImGui::SameLine(); + if (ImGui::Button(ls->DialogCancel.Get())) { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); } - ItemListEntries<T>(list); + ItemListEntries<T>(list, selectedIdx); } } // namespace @@ -112,13 +208,27 @@ void UI::ItemsTab() { auto ls = LocaleStrings::Instance.get(); auto& uis = UIState::GetInstance(); + constexpr float kAmount = 16.0f; + int id = 0; if (ImGui::CollapsingHeader(ls->ProductCategoryName.Get())) { + ImGui::PushID(id++); + ImGui::Indent(kAmount); ItemListEditor(uis.CurrentProject->Products); + ImGui::Unindent(kAmount); + ImGui::PopID(); } if (ImGui::CollapsingHeader(ls->FactoryCategoryName.Get())) { + ImGui::PushID(id++); + ImGui::Indent(kAmount); ItemListEditor(uis.CurrentProject->Factories); + ImGui::Unindent(kAmount); + ImGui::PopID(); } if (ImGui::CollapsingHeader(ls->CustomerCategoryName.Get())) { + ImGui::PushID(id++); + ImGui::Indent(kAmount); ItemListEditor(uis.CurrentProject->Customers); + ImGui::Unindent(kAmount); + ImGui::PopID(); } } diff --git a/core/src/UI/UI_MainWindow.cpp b/core/src/UI/UI_MainWindow.cpp index 15c28ff..661c535 100644 --- a/core/src/UI/UI_MainWindow.cpp +++ b/core/src/UI/UI_MainWindow.cpp @@ -15,10 +15,16 @@ namespace fs = std::filesystem; namespace { -void LoadProjectAt(const std::filesystem::path& path) { +bool LoadProjectAt(const std::filesystem::path& path) { auto& uis = UIState::GetInstance(); - auto project = Project::Load(path); - uis.SetCurrentProject(std::make_unique<Project>(std::move(project))); + try { + auto project = Project::Load(path); + uis.SetCurrentProject(std::make_unique<Project>(std::move(project))); + + return true; + } catch (const std::exception& e) { + return false; + } } void ProjectTab_Normal() { @@ -44,6 +50,8 @@ void ProjectTab_NoProject() { auto& gs = GlobalStates::GetInstance(); auto& uis = UIState::GetInstance(); + bool openedDummy = true; + bool openErrorDialog = false; static std::string projectName; static std::string dirName; static fs::path dirPath; @@ -61,13 +69,11 @@ void ProjectTab_NoProject() { if (ImGui::Button(ls->NewProject.Get())) { ImGui::SetNextWindowCentered(); - ImGui::SetNextWindowSizeRelScreen(0.5f, 0.5f); ImGui::OpenPopup(ls->NewProjectDialogTitle.Get()); } // Make it so that the modal dialog has a close button - bool newProjectDialogDummyTrue = true; - if (ImGui::BeginPopupModal(ls->NewProjectDialogTitle.Get(), &newProjectDialogDummyTrue)) { + if (ImGui::BeginPopupModal(ls->NewProjectDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::InputTextWithHint("##ProjectName", ls->NewProjectNameHint.Get(), &projectName); if (ImGui::InputTextWithHint("##ProjectPath", ls->NewProjectPathHint.Get(), &dirName)) { @@ -83,25 +89,15 @@ void ProjectTab_NoProject() { } if (projectName.empty()) { - ImGui::ErrorIcon(); - - ImGui::SameLine(); - ImGui::Text("%s", ls->NewProjectEmptyNameError.Get()); + ImGui::ErrorMessage("%s", ls->NewProjectEmptyNameError.Get()); } - if (!dirNameIsValid) { - ImGui::ErrorIcon(); - - ImGui::SameLine(); - ImGui::Text("%s", ls->NewProjectInvalidPathError.Get()); + ImGui::ErrorMessage("%s", ls->NewProjectInvalidPathError.Get()); } ImGui::Spacing(); - bool formValid = dirNameIsValid && !projectName.empty(); - - if (!formValid) ImGui::PushDisabled(); - if (ImGui::Button(ls->DialogConfirm.Get())) { + if (ImGui::Button(ls->DialogConfirm.Get(), !dirNameIsValid || projectName.empty())) { ImGui::CloseCurrentPopup(); auto project = Project::Create(std::move(projectName), dirPath); @@ -113,7 +109,6 @@ void ProjectTab_NoProject() { dirPath = fs::path{}; dirNameIsValid = false; } - if (!formValid) ImGui::PopDisabled(); ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { @@ -123,45 +118,72 @@ void ProjectTab_NoProject() { ImGui::EndPopup(); } + ImGui::SameLine(); if (ImGui::Button(ls->OpenProject.Get())) { auto selection = pfd::open_file(ls->OpenProjectDialogTitle.Get()).result(); if (!selection.empty()) { fs::path path(selection[0]); - LoadProjectAt(path); + openErrorDialog = !LoadProjectAt(path); } } + // TODO cleanup UI + // Recent projects + ImGui::Separator(); ImGui::Text("%s", ls->RecentProjects.Get()); + ImGui::SameLine(); if (ImGui::Button(ls->ClearRecentProjects.Get())) { gs.ClearRecentProjects(); } - auto& recentProjects = gs.GetRecentProjects(); - if (recentProjects.empty()) { + auto& rp = gs.GetRecentProjects(); + // End of vector is the most recently used, so that appending has less overhead + size_t toRemoveIdx = rp.size(); + + if (rp.empty()) { ImGui::Text("%s", ls->NoRecentProjectsMessage.Get()); - } - for (auto it = recentProjects.begin(); it != recentProjects.end(); ++it) { - auto& [path, recent] = *it; - ImGui::Text("%s", recent.c_str()); + } else { + for (auto it = rp.rbegin(); it != rp.rend(); ++it) { + auto& [path, recent] = *it; + ImGui::Text("%s", recent.c_str()); - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_EDIT)) { - LoadProjectAt(path); - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s", ls->OpenRecentProjectTooltip.Get()); - } + size_t idx = std::distance(it, rp.rend()) - 1; + ImGui::PushID(idx); - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_TRASH)) { - gs.RemoveRecentProject(std::distance(recentProjects.begin(), it)); - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s", ls->DeleteRecentProjectTooltip.Get()); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FOLDER_OPEN)) { + openErrorDialog = !LoadProjectAt(path / "cplt_project.json"); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", ls->OpenRecentProjectTooltip.Get()); + } + + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_TRASH)) { + toRemoveIdx = idx; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", ls->DeleteRecentProjectTooltip.Get()); + } + + ImGui::PopID(); } } + + if (toRemoveIdx != rp.size()) { + gs.RemoveRecentProject(toRemoveIdx); + } + + if (openErrorDialog) { + ImGui::SetNextWindowCentered(); + ImGui::OpenPopup(ls->Error.Get()); + } + if (ImGui::BeginPopupModal(ls->Error.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::ErrorMessage("%s", ls->InvalidProjectFormat.Get()); + ImGui::EndPopup(); + } } } // namespace diff --git a/core/src/UI/UI_Utils.cpp b/core/src/UI/UI_Utils.cpp index 615caae..06fd55e 100644 --- a/core/src/UI/UI_Utils.cpp +++ b/core/src/UI/UI_Utils.cpp @@ -4,18 +4,18 @@ #include <imgui.h> #include <imgui_internal.h> -void ImGui::SetNextWindowSizeRelScreen(float xPercent, float yPercent, ImGuiCond_ cond) { +void ImGui::SetNextWindowSizeRelScreen(float xPercent, float yPercent, ImGuiCond cond) { auto vs = ImGui::GetMainViewport()->Size; ImGui::SetNextWindowSize({ vs.x * xPercent, vs.y * yPercent }, cond); } -void ImGui::SetNextWindowCentered(ImGuiCond_ cond) { +void ImGui::SetNextWindowCentered(ImGuiCond cond) { auto vs = ImGui::GetMainViewport()->Size; ImGui::SetNextWindowPos({ vs.x / 2, vs.y / 2 }, cond, { 0.5f, 0.5f }); } void ImGui::PushDisabled() { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, false); + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f * ImGui::GetStyle().Alpha); } @@ -24,14 +24,46 @@ void ImGui::PopDisabled() { ImGui::PopStyleVar(); } +bool ImGui::Button(const char* label, bool disabled) { + return Button(label, ImVec2{}, disabled); +} + +bool ImGui::Button(const char* label, const ImVec2& sizeArg, bool disabled) { + if (disabled) PushDisabled(); + bool res = ImGui::Button(label, sizeArg); + if (disabled) PopDisabled(); + + return res; +} + void ImGui::ErrorIcon() { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 237 / 255.0f, 67 / 255.0f, 55 / 255.0f, 1.0f }); // #ED4337 ImGui::Text(ICON_FA_EXCLAMATION_CIRCLE); ImGui::PopStyleColor(); } +void ImGui::ErrorMessage(const char* fmt, ...) { + ErrorIcon(); + SameLine(); + + va_list args; + va_start(args, fmt); + TextV(fmt, args); + va_end(args); +} + void ImGui::WarningIcon() { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 255 / 255.0f, 184 / 255.0f, 24 / 255.0f, 1.0f }); // #FFB818 ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE); ImGui::PopStyleColor(); } + +void ImGui::WarningMessage(const char* fmt, ...) { + WarningIcon(); + SameLine(); + + va_list args; + va_start(args, fmt); + TextV(fmt, args); + va_end(args); +} |