#include "fiko/ui/hover_bilgi.hpp" #include #include #include "fiko/ui/animasyon.hpp" #include "fiko/ui/bilesen.hpp" #include "fiko/ui/tema.hpp" #include "imgui_internal.h" namespace fiko::ui { namespace { constexpr float OFSET_X = 18.0f; // imleçten sağa kayma constexpr float OFSET_Y = 12.0f; // imleçten aşağı kayma constexpr float PAD_X = 10.0f; // panel iç yatay boşluk constexpr float PAD_Y = 8.0f; // panel iç dikey boşluk constexpr float SATIR_H = 18.0f; // satır yüksekliği constexpr float SUTUN_BOSLUK = 14.0f; // etiket→değer arası minimum boşluk constexpr float BASLIK_H = 20.0f; constexpr float FS = 13.0f; // metin boyutu ImGuiID kimlikHash(const char* kimlik) { return ImHashStr(kimlik); } // Türe göre başlık ikonu + vurgu tonu (tema token). Nokta/Kenar/Yüz/Gövde ayrımı. const char* turIkon(HoverTur t) { switch (t) { case HoverTur::Nokta: return "•"; case HoverTur::Kenar: return "╱"; case HoverTur::Yuz: return "◈"; case HoverTur::Govde: return "◻"; default: return "◌"; } } const char* turAd(HoverTur t) { switch (t) { case HoverTur::Nokta: return "Nokta"; case HoverTur::Kenar: return "Kenar"; case HoverTur::Yuz: return "Yüz"; case HoverTur::Govde: return "Gövde"; default: return ""; } } const ImVec4& turRenk(const Tema& t, HoverTur h) { // Kenar/nokta ikincil (magenta), yüz/gövde birincil (cyan) — hızlı görsel ayrım. return (h == HoverTur::Kenar || h == HoverTur::Nokta) ? t.vurgu2 : t.vurgu; } } // namespace void hoverBilgiCiz(const char* kimlik, ImVec2 imlec, bool acik, const HoverIcerik& ic) { const bool doluMu = ic.tur != HoverTur::Yok && (ic.sayi > 0 || ic.baslik); const bool gorunur = acik && doluMu; const ImGuiID id = kimlikHash(kimlik); // Fade-in / fade-out: hedefe animf ile yaklaş. ~0 olunca hiç çizme. const float a = animf(id, gorunur ? 1.0f : 0.0f, 18.0f); if (a < 0.02f) return; const Tema& t = tema(); ImFont* f = ImGui::GetFont(); const ImVec4& vur = turRenk(t, ic.tur); // ---- Ölçüm: en geniş etiket + değer sütununu bul ---- const char* basIkon = turIkon(ic.tur); char basMetin[96]; if (ic.baslik) std::snprintf(basMetin, sizeof(basMetin), "%s %s", basIkon, ic.baslik); else std::snprintf(basMetin, sizeof(basMetin), "%s %s", basIkon, turAd(ic.tur)); float basGen = f->CalcTextSizeA(FS + 1.0f, FLT_MAX, 0.0f, basMetin).x; float etGen = 0.0f, degGen = 0.0f; for (int i = 0; i < ic.sayi; ++i) { if (ic.satirlar[i].etiket) etGen = ImMax(etGen, f->CalcTextSizeA(FS, FLT_MAX, 0.0f, ic.satirlar[i].etiket).x); if (ic.satirlar[i].deger) degGen = ImMax(degGen, f->CalcTextSizeA(FS, FLT_MAX, 0.0f, ic.satirlar[i].deger).x); } const float icerikGen = ImMax(basGen, etGen + SUTUN_BOSLUK + degGen); const float gen = icerikGen + PAD_X * 2.0f; const float yuk = BASLIK_H + (float)ic.sayi * SATIR_H + PAD_Y * 2.0f; // ---- Konum: imleç sağ-altı; viewport kenarına taşarsa çevir ---- ImGuiViewport* vp = ImGui::GetMainViewport(); if (ImGuiViewport* v = ImGui::FindViewportByID(ImGui::GetIO().MouseHoveredViewport)) vp = v; const float vMinX = vp->Pos.x + 4.0f, vMinY = vp->Pos.y + 4.0f; const float vMaxX = vp->Pos.x + vp->Size.x - 4.0f, vMaxY = vp->Pos.y + vp->Size.y - 4.0f; float px = imlec.x + OFSET_X; float py = imlec.y + OFSET_Y; if (px + gen > vMaxX) px = imlec.x - OFSET_X - gen; // sağa sığmıyor → sola if (px < vMinX) px = vMinX; if (py + yuk > vMaxY) py = imlec.y - OFSET_Y - yuk; // aşağı sığmıyor → yukarı if (py < vMinY) py = vMinY; const ImVec2 winMin{px, py}; const ImVec2 winMax{px + gen, py + yuk}; // ---- Overlay penceresi (şeffaf zemin, viewport'a bağlı — kendi OS penceresi yok) ---- ImGui::SetNextWindowViewport(vp->ID); ImGui::SetNextWindowPos(winMin); ImGui::SetNextWindowSize({gen, yuk}); ImGui::SetNextWindowBgAlpha(0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); char pencAd[96]; std::snprintf(pencAd, sizeof(pencAd), "##hover_bilgi_%08X", (unsigned)id); ImGui::Begin(pencAd, nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing); ImGui::PopStyleVar(3); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); ImDrawList* dl = ImGui::GetWindowDrawList(); // ---- Koyu cam-panel + neon kenar ---- const float kose = t.yuvarlak; glowCerceve(dl, winMin, winMax, vur, kose, 0.5f * a); const int vtx0 = dl->VtxBuffer.Size; dl->AddRectFilled(winMin, winMax, u32(t.panel, 0.97f * a), kose); ImGui::ShadeVertsLinearColorGradientKeepAlpha( dl, vtx0, dl->VtxBuffer.Size, winMin, {winMin.x, winMax.y}, u32(karisim(t.panel, vur, 0.10f), a), u32(karisim(t.panel, ImVec4{0, 0, 0, 1}, t.koyu ? 0.22f : 0.02f), a)); dl->AddRect(winMin, winMax, u32(vur, 0.55f * a), kose, 0, 1.3f); // Sol neon şerit (tür rengi vurgusu). dl->AddRectFilled(winMin, {winMin.x + 3.0f, winMax.y}, u32(vur, 0.85f * a), kose, ImDrawFlags_RoundCornersLeft); // ---- Başlık: ikon + tür/ad ---- const float ix = winMin.x + PAD_X; float y = winMin.y + PAD_Y; dl->AddText(f, FS + 1.0f, {ix, y}, u32(vur, a), basMetin); y += BASLIK_H; dl->AddLine({ix, y - 3.0f}, {winMax.x - PAD_X, y - 3.0f}, u32(t.kenar, 0.7f * a), 1.0f); // ---- Satırlar: etiket (soluk, sol) + değer (metin, sağ hizalı) ---- for (int i = 0; i < ic.sayi; ++i) { const HoverSatir& s = ic.satirlar[i]; if (s.etiket) dl->AddText(f, FS, {ix, y + 1.0f}, u32(t.metinSoluk, a), s.etiket); if (s.deger) { const float dw = f->CalcTextSizeA(FS, FLT_MAX, 0.0f, s.deger).x; dl->AddText(f, FS, {winMax.x - PAD_X - dw, y + 1.0f}, u32(t.metin, a), s.deger); } y += SATIR_H; } ImGui::End(); } } // namespace fiko::ui