#include "CCImGuiEXT.h" #include "imgui_impl_cocos2dx.h" NS_CC_EXT_BEGIN static ImGuiEXT* _instance = nullptr; std::function ImGuiEXT::_onInit; void ImGuiEXT::init() { ImGui_ImplCocos2dx_Init(true); } ImGuiEXT* ImGuiEXT::getInstance() { if(_instance == nullptr) { _instance = new ImGuiEXT(); _instance->init(); if (_onInit) _onInit(_instance); } return _instance; } void ImGuiEXT::destroyInstance() { if (_instance) { delete _instance; ImGui_ImplCocos2dx_Shutdown(); _instance = nullptr; } } void ImGuiEXT::setOnInit(const std::function& callBack) { _onInit = callBack; } void ImGuiEXT::onDraw() { // clear things from last frame usedCCRefIdMap.clear(); usedCCRef.clear(); // drawing commands auto iter = _callPiplines.begin(); for (; iter != _callPiplines.end(); ++iter) { iter->second(); } // commands will be processed after update } void ImGuiEXT::addCallback(const std::function& callBack, const std::string& name) { _callPiplines[name] = callBack; } void ImGuiEXT::removeCallback(const std::string& name) { const auto iter = _callPiplines.find(name); if (iter != _callPiplines.end()) _callPiplines.erase(iter); } static std::tuple getTextureUV(Sprite* sp) { ImVec2 uv0, uv1; if (!sp || !sp->getTexture()) return { uv0,uv1 }; const auto rect = sp->getTextureRect(); const auto tex = sp->getTexture(); const float atlasWidth = (float)tex->getPixelsWide(); const float atlasHeight = (float)tex->getPixelsHigh(); uv0.x = rect.origin.x / atlasWidth; uv0.y = rect.origin.y / atlasHeight; uv1.x = (rect.origin.x + rect.size.width) / atlasWidth; uv1.y = (rect.origin.y + rect.size.height) / atlasHeight; return { uv0,uv1 }; } void ImGuiEXT::image(Texture2D* tex, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) { if (!tex) return; auto size_ = size; if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); ImGui::PushID(getCCRefId(tex)); ImGui::Image((ImTextureID)tex, size_, uv0, uv1, tint_col, border_col); ImGui::PopID(); } void ImGuiEXT::image(Sprite* sprite, const ImVec2& size, const ImVec4& tint_col, const ImVec4& border_col) { if (!sprite || !sprite->getTexture()) return; auto size_ = size; const auto rect = sprite->getTextureRect(); if (size_.x <= 0.f) size_.x = rect.size.width; if (size_.y <= 0.f) size_.y = rect.size.height; ImVec2 uv0, uv1; std::tie(uv0, uv1) = getTextureUV(sprite); ImGui::PushID(getCCRefId(sprite)); ImGui::Image((ImTextureID)sprite->getTexture(), size_, uv0, uv1, tint_col, border_col); ImGui::PopID(); } bool ImGuiEXT::imageButton(Texture2D* tex, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { if (!tex) return false; auto size_ = size; if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); ImGui::PushID(getCCRefId(tex)); const auto ret = ImGui::ImageButton((ImTextureID)tex, size_, uv0, uv1, frame_padding, bg_col, tint_col); ImGui::PopID(); return ret; } bool ImGuiEXT::imageButton(Sprite* sprite, const ImVec2& size, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { if (!sprite || !sprite->getTexture()) return false; auto size_ = size; const auto rect = sprite->getTextureRect(); if (size_.x <= 0.f) size_.x = rect.size.width; if (size_.y <= 0.f) size_.y = rect.size.height; ImVec2 uv0, uv1; std::tie(uv0, uv1) = getTextureUV(sprite); ImGui::PushID(getCCRefId(sprite)); const auto ret = ImGui::ImageButton((ImTextureID)sprite->getTexture(), size_, uv0, uv1, frame_padding, bg_col, tint_col); ImGui::PopID(); return ret; } void ImGuiEXT::node(Node* node, const ImVec4& tint_col, const ImVec4& border_col) { if (!node) return; const auto size = node->getContentSize(); const auto pos = ImGui::GetCursorScreenPos(); Mat4 tr; tr.m[5] = -1; tr.m[12] = pos.x; tr.m[13] = pos.y + size.height; if (border_col.w > 0.f) { tr.m[12] += 1; tr.m[13] += 1; } node->setNodeToParentTransform(tr); ImGui::PushID(getCCRefId(node)); ImGui::Image((ImTextureID)node, ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); ImGui::PopID(); } bool ImGuiEXT::nodeButton(Node* node, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { if (!node) return false; const auto size = node->getContentSize(); const auto pos = ImGui::GetCursorScreenPos(); Mat4 tr; tr.m[5] = -1; tr.m[12] = pos.x; tr.m[13] = pos.y + size.height; if (frame_padding >= 0) { tr.m[12] += (float)frame_padding; tr.m[13] += (float)frame_padding; } else { tr.m[12] += ImGui::GetStyle().FramePadding.x; tr.m[13] += ImGui::GetStyle().FramePadding.y; } node->setNodeToParentTransform(tr); ImGui::PushID(getCCRefId(node)); const auto ret = ImGui::ImageButton((ImTextureID)node, ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), frame_padding, bg_col, tint_col); ImGui::PopID(); return ret; } std::tuple ImGuiEXT::useTexture(Texture2D* texture) { if (!texture) return { nullptr,0 }; return { (ImTextureID)texture,getCCRefId(texture) }; } std::tuple ImGuiEXT::useSprite(Sprite* sprite) { if (!sprite || !sprite->getTexture()) return { nullptr,{},{},0 }; ImVec2 uv0, uv1; std::tie(uv0, uv1) = getTextureUV(sprite); return { (ImTextureID)sprite->getTexture(),uv0,uv1,getCCRefId(sprite) }; } std::tuple ImGuiEXT::useNode(Node* node, const ImVec2& pos) { if (!node) return { nullptr,{},{},0 }; const auto size = node->getContentSize(); Mat4 tr; tr.m[5] = -1; tr.m[12] = pos.x; tr.m[13] = pos.y + size.height; node->setNodeToParentTransform(tr); return { (ImTextureID)node,pos,ImVec2(pos.x + size.width,pos.y + size.height),getCCRefId(node) }; } void ImGuiEXT::setNodeColor(Node* node, const ImVec4& col) { if (node) { node->setColor({ uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255) }); node->setOpacity(uint8_t(col.w * 255)); } } void ImGuiEXT::setNodeColor(Node* node, ImGuiCol col) { if (node && 0 <= col && col < ImGuiCol_COUNT) setNodeColor(node, ImGui::GetStyleColorVec4(col)); } void ImGuiEXT::setLabelColor(Label* label, const ImVec4& col) { if (label) { label->setTextColor( { uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255),uint8_t(col.w * 255) }); } } void ImGuiEXT::setLabelColor(Label* label, bool disabled) { if (label) setLabelColor(label, ImGui::GetStyleColorVec4(disabled ? ImGuiCol_TextDisabled : ImGuiCol_Text)); } void ImGuiEXT::setLabelColor(Label* label, ImGuiCol col) { if (label && 0 <= col && col < ImGuiCol_COUNT) setLabelColor(label, ImGui::GetStyleColorVec4(col)); } ImWchar* ImGuiEXT::addGlyphRanges(const std::string& key, const std::vector& ranges) { auto it = glyphRanges.find(key); // the pointer must be persistant, do not replace if (it != glyphRanges.end()) return it->second.data(); glyphRanges[key] = ranges; if (ranges.empty()) glyphRanges[key].push_back(0); return glyphRanges[key].data(); } void ImGuiEXT::mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end) { if (!dst || !src || start > end) return; for (auto i = start; i <= end; ++i) { const auto g = src->FindGlyphNoFallback(i); if (g) { // TODO // dst->AddGlyph(g->Codepoint, g->X0, g->Y0, g->X1, g->Y1, g->U0, g->V0, g->U1, g->V1, g->AdvanceX); } } dst->BuildLookupTable(); } int ImGuiEXT::getCCRefId(Ref* p) { int id = 0; const auto it = usedCCRefIdMap.find(p); if (it == usedCCRefIdMap.end()) { usedCCRefIdMap[p] = 0; usedCCRef.pushBack(p); } else id = ++it->second; // BKDR hash constexpr unsigned int seed = 131; unsigned int hash = 0; for (auto i = 0u; i < sizeof(void*); ++i) hash = hash * seed + ((const char*)&p)[i]; for (auto i = 0u; i < sizeof(int); ++i) hash = hash * seed + ((const char*)&id)[i]; return (int)hash; } #if defined(HAVE_IMGUI_MARKDOWN) #include "imgui_markdown/imgui_markdown.h" static ImGuiEXT::MdLinkCallback ImGuiMarkdownLinkCallback = nullptr; static ImGuiEXT::MdImageCallback ImGuiMarkdownImageCallback = nullptr; static ImGui::MarkdownImageData ImGuiMarkdownInvalidImageData = { false, false, nullptr, {0.f, 0.f} }; void MarkdownLinkCallback(ImGui::MarkdownLinkCallbackData data) { if (ImGuiMarkdownLinkCallback) { ImGuiMarkdownLinkCallback( { data.text, (size_t)data.textLength }, { data.link, (size_t)data.linkLength }, data.isImage); } } ImGui::MarkdownImageData MarkdownImageCallback(ImGui::MarkdownLinkCallbackData data) { if (!data.isImage || !ImGuiMarkdownImageCallback) return ImGuiMarkdownInvalidImageData; Sprite* sp; ImVec2 size; ImVec4 tint_col; ImVec4 border_col; std::tie(sp, size, tint_col, border_col) = ImGuiMarkdownImageCallback( { data.text, (size_t)data.textLength }, { data.link, (size_t)data.linkLength }); if(!sp || !sp->getTexture()) return ImGuiMarkdownInvalidImageData; auto size_ = size; const auto rect = sp->getTextureRect(); if (size_.x <= 0.f) size_.x = rect.size.width; if (size_.y <= 0.f) size_.y = rect.size.height; ImVec2 uv0, uv1; std::tie(uv0, uv1) = getTextureUV(sp); ImGuiEXT::getInstance()->getCCRefId(sp); return { true, true, (ImTextureID)sp->getTexture(), size_,uv0, uv1, tint_col, border_col }; } static std::string ImGuiMarkdownLinkIcon; static ImGui::MarkdownConfig ImGuiMarkdownConfig = { MarkdownLinkCallback, MarkdownImageCallback, "" }; void ImGuiEXT::setMarkdownLinkCallback(const MdLinkCallback& f) { ImGuiMarkdownLinkCallback = f; } void ImGuiEXT::setMarkdownImageCallback(const MdImageCallback& f) { ImGuiMarkdownImageCallback = f; } void ImGuiEXT::setMarkdownFont(int index, ImFont* font, bool seperator, float scale) { if (index < 0 || index >= ImGui::MarkdownConfig::NUMHEADINGS) return; ImGuiMarkdownConfig.headingFormats[index] = { font,seperator }; ImGuiMarkdownConfig.headingScales[index] = scale; } void ImGuiEXT::setMarkdownLinkIcon(const std::string& icon) { ImGuiMarkdownLinkIcon = icon; ImGuiMarkdownConfig.linkIcon = ImGuiMarkdownLinkIcon.c_str(); } void ImGuiEXT::markdown(const std::string& content) { ImGui::Markdown(content.c_str(), content.size(), ImGuiMarkdownConfig); } #endif NS_CC_EXT_END