diff --git a/src/imrad.cpp b/src/imrad.cpp index 50d93af..86420a5 100644 --- a/src/imrad.cpp +++ b/src/imrad.cpp @@ -32,6 +32,7 @@ #include "ui_binding.h" #include "ui_combo_dlg.h" #include "ui_horiz_layout.h" +#include "ui_clone_style.h" //must come last #define STB_IMAGE_IMPLEMENTATION @@ -630,6 +631,42 @@ void GetStyles() } } +const std::array& +GetCtxColors(const std::string& styleName) +{ + static const std::array classic{ + IM_COL32(255, 255, 0, 128), + IM_COL32(255, 0, 0, 255), + IM_COL32(128, 128, 255, 255), + IM_COL32(255, 0, 255, 255), + IM_COL32(0, 255, 255, 255), + IM_COL32(0, 255, 0, 255), + }; + static const std::array light { + IM_COL32(255, 0, 0, 255), + IM_COL32(255, 0, 0, 255), + IM_COL32(128, 128, 255, 255), + IM_COL32(255, 0, 255, 255), + IM_COL32(0, 128, 128, 255), + IM_COL32(0, 255, 0, 255), + }; + static const std::array dark{ + IM_COL32(255, 255, 0, 128), + IM_COL32(255, 0, 0, 255), + IM_COL32(128, 128, 255, 255), + IM_COL32(255, 0, 255, 255), + IM_COL32(0, 255, 255, 255), + IM_COL32(0, 255, 0, 255), + }; + + if (styleName == "Light") + return light; + else if (styleName == "Dark") + return dark; + else + return classic; +} + void LoadStyle() { if (!reloadStyle) @@ -664,40 +701,19 @@ void LoadStyle() { ImGui::StyleColorsClassic(&ctx.style); ctx.fontNames = { "" }; - ctx.colors = { - IM_COL32(255, 255, 0, 128), - IM_COL32(255, 0, 0, 255), - IM_COL32(128, 128, 255, 255), - IM_COL32(255, 0, 255, 255), - IM_COL32(0, 255, 255, 255), - IM_COL32(0, 255, 0, 255), - }; + ctx.colors = GetCtxColors(styleName); } else if (styleName == "Light") { ImGui::StyleColorsLight(&ctx.style); ctx.fontNames = { "" }; - ctx.colors = { - IM_COL32(255, 0, 0, 255), - IM_COL32(255, 0, 0, 255), - IM_COL32(128, 128, 255, 255), - IM_COL32(255, 0, 255, 255), - IM_COL32(0, 128, 128, 255), - IM_COL32(0, 255, 0, 255), - }; + ctx.colors = GetCtxColors(styleName); } else if (styleName == "Dark") { ImGui::StyleColorsDark(&ctx.style); ctx.fontNames = { "" }; - ctx.colors = { - IM_COL32(255, 255, 0, 128), - IM_COL32(255, 0, 0, 255), - IM_COL32(128, 128, 255, 255), - IM_COL32(255, 0, 255, 255), - IM_COL32(0, 255, 255, 255), - IM_COL32(0, 255, 0, 255), - }; + ctx.colors = GetCtxColors(styleName); } else { @@ -744,6 +760,80 @@ void LoadStyle() ImGui_ImplOpenGL3_CreateFontsTexture(); } +void DoCloneStyle(const std::string& name) +{ + auto FormatClr = [](ImU32 c) { + std::ostringstream os; + os << (c & 0xff) << " " << + ((c >> 8) & 0xff) << " " << + ((c >> 16) & 0xff) << " " << + ((c >> 24) & 0xff); + return os.str(); + }; + + std::string from = fileTabs[activeTab].styleName; + std::string path = "style/" + name + ".ini"; + try + { + if (from == "Classic" || from == "Dark" || from == "Light") + { + ImGuiStyle style; + if (from == "Dark") + ImGui::StyleColorsDark(&style); + else if (from == "Light") + ImGui::StyleColorsLight(&style); + else + ImGui::StyleColorsClassic(&style); + + std::map extra; + const auto& colors = GetCtxColors(from); +#define SET_CLR(a) extra[std::string("imrad.colors.") + #a] = FormatClr(colors[UIContext::Color::a]); + SET_CLR(Selected); + SET_CLR(Hovered); + SET_CLR(Snap1); + SET_CLR(Snap2); + SET_CLR(Snap3); + SET_CLR(Snap4); + SET_CLR(Snap5); +#undef SET_CLR + ImRad::SaveStyle(path, &style, extra); + } + else + { + fs::copy_file("style/" + from + ".ini", path, fs::copy_options::overwrite_existing); + } + + fileTabs[activeTab].styleName = name; + if (!stx::count_if(styleNames, [&](const auto& s) { return s.first == name; })) + styleNames.push_back({ name, path }); + } + catch (std::exception& e) { + messageBox.title = "error"; + messageBox.message = e.what(); + messageBox.buttons = ImRad::Ok; + messageBox.OpenPopup(); + } +} + +void CloneStyle() +{ + cloneStyle.OpenPopup([](ImRad::ModalResult mr) + { + std::string path = "style/" + cloneStyle.styleName + ".ini"; + if (fs::exists(path)) { + messageBox.title = "Confirmation"; + messageBox.message = "Overwrite existing style?"; + messageBox.buttons = ImRad::Yes | ImRad::No; + messageBox.OpenPopup([=](ImRad::ModalResult mr) { + if (mr == ImRad::Yes) + DoCloneStyle(cloneStyle.styleName); + }); + } + else + DoCloneStyle(cloneStyle.styleName); + }); +} + void DockspaceUI() { // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, @@ -904,6 +994,11 @@ void ToolbarUI() ImGui::EndCombo(); } ImGui::SameLine(); + if (ImGui::Button(ICON_FA_CLONE)) + CloneStyle(); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + ImGui::SetTooltip("Clone Style"); + ImGui::SameLine(); ImGui::Text("Units"); ImGui::SameLine(); ImGui::SetNextItemWidth(100); @@ -1289,6 +1384,8 @@ void PopupUI() bindingDlg.Draw(); horizLayout.Draw(); + + cloneStyle.Draw(); } void Draw() diff --git a/src/imrad.h b/src/imrad.h index f34c298..beb7645 100644 --- a/src/imrad.h +++ b/src/imrad.h @@ -322,22 +322,25 @@ Texture LoadTextureFromFile(std::string_view filename); #endif //For debugging pruposes -inline void SaveStyle(std::string_view fname) +inline void SaveStyle(std::string_view fname_, const ImGuiStyle* src = nullptr, const std::map& extra = {}) { - std::ofstream fout(std::string(fname.begin(), fname.end())); - const auto& s = ImGui::GetStyle(); - + const ImGuiStyle* style = src ? src : &ImGui::GetStyle(); + std::string fname(fname_.begin(), fname_.end()); + std::ofstream fout(fname); + if (!fout) + throw std::runtime_error("can't write '" + fname + "'"); + fout << "[colors]\n"; for (int i = 0; i < ImGuiCol_COUNT; ++i) { fout << ImGui::GetStyleColorName(i) << " = "; - const auto& clr = s.Colors[i]; + const auto& clr = style->Colors[i]; fout << int(clr.x * 255) << " " << int(clr.y * 255) << " " << int(clr.z * 255) << " " << int(clr.w * 255) << "\n"; } fout << "\n[variables]\n"; -#define WRITE_FLT(a) fout << #a " = " << s.a << "\n" -#define WRITE_VEC(a) fout << #a " = " << s.a.x << " " << s.a.y << "\n" +#define WRITE_FLT(a) fout << #a " = " << style->a << "\n" +#define WRITE_VEC(a) fout << #a " = " << style->a.x << " " << style->a.y << "\n" WRITE_FLT(Alpha); WRITE_FLT(DisabledAlpha); @@ -365,12 +368,20 @@ inline void SaveStyle(std::string_view fname) #undef WRITE_VEC fout << "\n[fonts]\n"; - fout << "# Default = \"Roboto-Medium.ttf\" size 20\n"; + fout << "Default = \"Roboto-Medium.ttf\" size 20\n"; - fout << "\n[imrad.colors]\n"; - fout << "# Hovered 255 255 0 255\n"; - fout << "# Selected 255 0 0 255\n"; - fout << "# Snap1 ...\n"; + std::string lastSection; + for (const auto& kv : extra) + { + size_t i = kv.first.find_last_of('.'); + if (i == std::string::npos) + continue; + if (kv.first.substr(0, i) != lastSection) { + lastSection = kv.first.substr(0, i); + fout << "\n[" << lastSection << "]\n"; + } + fout << kv.first.substr(i + 1) << " = " << kv.second << "\n"; + } } //This function can be used in your code to load style and fonts from the INI file diff --git a/src/ui_clone_style.cpp b/src/ui_clone_style.cpp new file mode 100644 index 0000000..9a26841 --- /dev/null +++ b/src/ui_clone_style.cpp @@ -0,0 +1,94 @@ +// Generated with ImRAD 0.7 +// visit https://github.com/tpecholt/imrad + +#include "ui_clone_style.h" +#include "ui_message_box.h" + +CloneStyle cloneStyle; + + +void CloneStyle::OpenPopup(std::function clb) +{ + callback = clb; + modalResult = ImRad::None; + animator.Start(ImRad::Animator::OpenPopup); + ImGui::OpenPopup(ID); + Init(); +} + +void CloneStyle::ClosePopup(ImRad::ModalResult mr) +{ + modalResult = mr; + animator.Start(ImRad::Animator::ClosePopup); +} + +void CloneStyle::Init() +{ + // TODO: Add your code here + styleName = ""; +} + +void CloneStyle::Draw() +{ + /// @style Dark + /// @unit px + /// @begin TopWindow + auto* ioUserData = (ImRad::IOUserData*)ImGui::GetIO().UserData; + ID = ImGui::GetID("###CloneStyle"); + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), 0, { 0.5f, 0.5f }); //Center + ImGui::SetNextWindowSize({ 250, 120 }); + bool tmpOpen = true; + if (ImGui::BeginPopupModal("Clone Style###CloneStyle", &tmpOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) + { + if (modalResult != ImRad::None) + { + ImGui::CloseCurrentPopup(); + if (modalResult != ImRad::Cancel) callback(modalResult); + } + /// @separator + + // TODO: Add Draw calls of dependent popup windows here + messageBox.Draw(); + + /// @begin Input + if (ImGui::IsWindowAppearing()) + ImGui::SetKeyboardFocusHere(); + ImGui::SetNextItemWidth(-1); + ImGui::InputTextWithHint("##styleName", "New style name", &styleName, ImGuiInputTextFlags_CharsNoBlank); + if (ImGui::IsItemActive()) + ioUserData->imeType = ImRad::ImeText; + /// @end Input + + /// @begin Table + ImRad::Spacing(3); + if (ImGui::BeginTable("table1", 3, ImGuiTableFlags_NoPadOuterX | ImGuiTableFlags_NoPadInnerX, { 0, 0 })) + { + ImGui::TableSetupColumn("left-stretch", ImGuiTableColumnFlags_WidthStretch, 0); + ImGui::TableSetupColumn("content", ImGuiTableColumnFlags_WidthFixed, 0); + ImGui::TableSetupColumn("right-stretch", ImGuiTableColumnFlags_WidthStretch, 0); + ImGui::TableNextRow(0, 0); + ImGui::TableSetColumnIndex(0); + /// @separator + + /// @begin Button + ImRad::TableNextColumn(1); + ImGui::BeginDisabled(styleName==""||styleName=="Classic"||styleName=="Dark"||styleName=="Light"); + if (ImGui::Button("OK", { 90, 30 }) || + (!ImRad::IsItemDisabled() && ImGui::IsKeyPressed(ImGuiKey_Enter, false))) + { + ClosePopup(ImRad::Ok); + } + ImGui::EndDisabled(); + /// @end Button + + + /// @separator + ImGui::EndTable(); + } + /// @end Table + + /// @separator + ImGui::EndPopup(); + } + /// @end TopWindow +} diff --git a/src/ui_clone_style.h b/src/ui_clone_style.h new file mode 100644 index 0000000..75e47c1 --- /dev/null +++ b/src/ui_clone_style.h @@ -0,0 +1,30 @@ +// Generated with ImRAD 0.7 +// visit https://github.com/tpecholt/imrad + +#pragma once +#include "imrad.h" + +class CloneStyle +{ +public: + /// @begin interface + void OpenPopup(std::function clb = [](ImRad::ModalResult){}); + void ClosePopup(ImRad::ModalResult mr); + void Draw(); + + std::string styleName; + /// @end interface + +private: + /// @begin impl + void Init(); + + ImGuiID ID = 0; + ImRad::ModalResult modalResult; + ImRad::Animator animator; + std::function callback; + + /// @end impl +}; + +extern CloneStyle cloneStyle;