#include "fiko/ui/kesit_tarayici.hpp" #include #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 { void metniOrtala(ImDrawList* dl, ImVec2 merkez, float boyut, ImU32 renk, const char* metin) { ImFont* f = ImGui::GetFont(); const ImVec2 mb = f->CalcTextSizeA(boyut, FLT_MAX, 0.0f, metin); dl->AddText(f, boyut, {merkez.x - mb.x * 0.5f, merkez.y - mb.y * 0.5f}, renk, metin); } // Büyük okunur değer HUD baloncuğu (ekran-sabit, koyu zemin). Playhead üstünde. void degerHud(ImDrawList* dl, ImVec2 uc, const char* metin, float belir) { if (belir <= 0.01f) return; const Tema& t = tema(); ImFont* f = ImGui::GetFont(); const float fs = 15.0f; const ImVec2 mb = f->CalcTextSizeA(fs, FLT_MAX, 0.0f, metin); const float pd = 7.0f; const float w = mb.x + pd * 2.0f, h = mb.y + pd * 1.4f; const ImVec2 mn{uc.x - w * 0.5f, uc.y - h - 12.0f}; const ImVec2 mx{mn.x + w, mn.y + h}; // dış glow + koyu hap zemin glowCerceve(dl, mn, mx, t.vurgu, t.yuvarlak, 0.45f * belir); dl->AddRectFilled(mn, mx, u32(t.koyu ? ImVec4{0.04f, 0.05f, 0.07f, 0.96f} : ImVec4{0.12f, 0.13f, 0.17f, 0.97f}, belir), t.yuvarlak); dl->AddRect(mn, mx, u32(t.vurgu, 0.55f * belir), t.yuvarlak, 0, 1.2f); // ok (baloncuk → playhead) const float ax = uc.x; dl->AddTriangleFilled({ax - 5.0f, mx.y - 0.5f}, {ax + 5.0f, mx.y - 0.5f}, {ax, mx.y + 6.0f}, u32(t.vurgu, 0.9f * belir)); dl->AddText(f, fs, {mn.x + pd, mn.y + pd * 0.7f}, u32(t.metin, belir), metin); } // Renk rampaları (jet / turbo / viridis benzeri). t: 0..1 → RGB. ImVec4 rampaRenk(int tip, float u) { u = ImClamp(u, 0.0f, 1.0f); auto lerp = [](const ImVec4& a, const ImVec4& b, float k) { return ImVec4{a.x + (b.x - a.x) * k, a.y + (b.y - a.y) * k, a.z + (b.z - a.z) * k, 1.0f}; }; if (tip == 2) { // viridis benzeri (koyu mor → yeşil → sarı) static const ImVec4 c[5] = {{0.27f, 0.00f, 0.33f, 1}, {0.23f, 0.32f, 0.55f, 1}, {0.13f, 0.57f, 0.55f, 1}, {0.37f, 0.79f, 0.38f, 1}, {0.99f, 0.91f, 0.14f, 1}}; const float s = u * 4.0f; const int i = ImMin((int)s, 3); return lerp(c[i], c[i + 1], s - (float)i); } if (tip == 1) { // turbo (koyu mavi → cyan → yeşil → sarı → kırmızı → koyu kırmızı) static const ImVec4 c[6] = {{0.19f, 0.07f, 0.23f, 1}, {0.13f, 0.56f, 0.95f, 1}, {0.20f, 0.90f, 0.60f, 1}, {0.85f, 0.95f, 0.18f, 1}, {0.97f, 0.42f, 0.11f, 1}, {0.60f, 0.05f, 0.06f, 1}}; const float s = u * 5.0f; const int i = ImMin((int)s, 4); return lerp(c[i], c[i + 1], s - (float)i); } // jet (mavi → cyan → yeşil → sarı → kırmızı) static const ImVec4 c[5] = {{0.00f, 0.10f, 0.90f, 1}, {0.00f, 0.80f, 0.95f, 1}, {0.25f, 0.90f, 0.30f, 1}, {0.98f, 0.85f, 0.15f, 1}, {0.95f, 0.20f, 0.15f, 1}}; const float s = u * 4.0f; const int i = ImMin((int)s, 3); return lerp(c[i], c[i + 1], s - (float)i); } // Ortak yatay ray + neon dolgu + nabızlı playhead (kesit & sonuç paylaşır). // oran: 0..1 playhead konumu, aktifBelir: HUD/tutamaç belirginliği. void scrubberRay(ImDrawList* dl, ImVec2 p, float gen, float cy, float oran, float aktifBelir, float& outHeadX) { const Tema& t = tema(); const float ray0 = p.x + 10.0f, ray1 = p.x + gen - 10.0f; outHeadX = ray0 + (ray1 - ray0) * ImClamp(oran, 0.0f, 1.0f); // ray zemin dl->AddRectFilled({ray0, cy - 3.0f}, {ray1, cy + 3.0f}, u32(t.cerceve), 3.0f); // geçmiş: neon gradient dolgu (vurgu → vurgu2) const int vtx0 = dl->VtxBuffer.Size; dl->AddRectFilled({ray0, cy - 3.0f}, {outHeadX, cy + 3.0f}, u32(t.vurgu), 3.0f); ImGui::ShadeVertsLinearColorGradientKeepAlpha(dl, vtx0, dl->VtxBuffer.Size, {ray0, cy}, {outHeadX, cy}, u32(t.vurgu), u32(t.vurgu2)); dl->AddRectFilled({ray0, cy - 4.5f}, {outHeadX, cy + 4.5f}, u32(t.vurgu, 0.10f * t.glowSiddet), 4.5f); // playhead (nabızlı iz + tutamaç) const float nb = 0.5f + 0.5f * nabiz(1.4f); dl->AddLine({outHeadX, cy - 12.0f}, {outHeadX, cy + 12.0f}, u32(t.vurgu2, 0.20f * t.glowSiddet * (0.6f + 0.4f * nb)), 5.0f); dl->AddCircleFilled({outHeadX, cy}, 8.0f + 2.0f * aktifBelir, u32(t.vurgu2, 0.22f)); dl->AddCircleFilled({outHeadX, cy}, 6.0f, u32(t.metin)); dl->AddCircle({outHeadX, cy}, 6.0f, u32(t.vurgu2), 0, 1.8f); } } // namespace bool kesitTarayici(const char* kimlik, float* deger, float mn, float mx, const char* birim) { const Tema& t = tema(); ImGui::PushID(kimlik); const float gen = ImGui::GetContentRegionAvail().x; const float yk = 46.0f; const ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::InvisibleButton("##kesit", {gen, yk}); const ImGuiID id = ImGui::GetItemID(); const bool aktif = ImGui::IsItemActive(); const bool hover = ImGui::IsItemHovered(); const float aralik = (mx - mn) > 1e-6f ? (mx - mn) : 1.0f; const float ray0 = p.x + 10.0f, ray1 = p.x + gen - 10.0f; const float cy = p.y + yk * 0.60f; bool degisti = false; if (aktif) { const float fx = ImGui::GetMousePos().x; float v = mn + (fx - ray0) / (ray1 - ray0) * aralik; v = ImClamp(v, mn, mx); if (v != *deger) { *deger = v; degisti = true; } } const float h = animf(id, (hover || aktif) ? 1.0f : 0.0f, 12.0f); ImDrawList* dl = ImGui::GetWindowDrawList(); const float oran = (*deger - mn) / aralik; float headX = 0.0f; scrubberRay(dl, p, gen, cy, oran, h, headX); // min/max uç etiketleri ImFont* f = ImGui::GetFont(); char uc[32]; std::snprintf(uc, sizeof(uc), "%.1f", mn); dl->AddText(f, 10.0f, {ray0 - 2.0f, cy + 9.0f}, u32(t.metinSoluk, 0.8f), uc); std::snprintf(uc, sizeof(uc), "%.1f", mx); const ImVec2 mb = f->CalcTextSizeA(10.0f, FLT_MAX, 0.0f, uc); dl->AddText(f, 10.0f, {ray1 - mb.x + 2.0f, cy + 9.0f}, u32(t.metinSoluk, 0.8f), uc); // büyük değer HUD (sürükleme/hover'da belirir) char hud[48]; std::snprintf(hud, sizeof(hud), birim && birim[0] ? "%.2f %s" : "%.2f", *deger, birim ? birim : ""); degerHud(dl, {headX, cy}, hud, ImMax(h, aktif ? 1.0f : 0.0f)); ImGui::PopID(); return degisti; } bool sonucTarayici(const char* kimlik, int* kare, int kareSayi, SonucTarayiciDurum* durum, const char* etiket) { if (kareSayi <= 0) return false; const Tema& t = tema(); ImGui::PushID(kimlik); const int sonKare = kareSayi - 1; *kare = ImClamp(*kare, 0, sonKare); bool degisti = false; // ── kontrol satırı: ⏮ ⏯ ⏭ + etiket + kare sayacı ── if (ikonButon("⏮", "Başa")) { if (*kare != 0) { *kare = 0; degisti = true; } durum->oynat = false; } ImGui::SameLine(); if (ikonButon("⏪", "Geri adım")) { if (*kare > 0) { (*kare)--; degisti = true; } durum->oynat = false; } ImGui::SameLine(); if (ikonButon(durum->oynat ? "⏸" : "▶", durum->oynat ? "Duraklat" : "Oynat", durum->oynat)) { durum->oynat = !durum->oynat; if (durum->oynat && *kare >= sonKare) { *kare = 0; degisti = true; } durum->_akis = 0.0f; } ImGui::SameLine(); if (ikonButon("⏩", "İleri adım")) { if (*kare < sonKare) { (*kare)++; degisti = true; } durum->oynat = false; } ImGui::SameLine(); if (ikonButon("⏭", "Sona")) { if (*kare != sonKare) { *kare = sonKare; degisti = true; } durum->oynat = false; } ImGui::SameLine(0, 14); ImGui::AlignTextToFramePadding(); if (etiket && etiket[0]) { ImGui::TextColored(t.metinSoluk, "%s", etiket); ImGui::SameLine(0, 8); } ImGui::Text("%d / %d", *kare + 1, kareSayi); // ── playhead şeridi ── const float gen = ImGui::GetContentRegionAvail().x; const float yk = 40.0f; const ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::InvisibleButton("##sonuc", {gen, yk}); const ImGuiID id = ImGui::GetItemID(); const bool aktif = ImGui::IsItemActive(); const bool hover = ImGui::IsItemHovered(); const float ray0 = p.x + 10.0f, ray1 = p.x + gen - 10.0f; const float cy = p.y + yk * 0.5f; // kullanıcı tutunca oynatma durur, kareyi sürükle if (aktif) { durum->oynat = false; const float fx = ImGui::GetMousePos().x; const float u = ImClamp((fx - ray0) / (ray1 - ray0), 0.0f, 1.0f); const int yeni = (int)std::lround(u * (float)sonKare); if (yeni != *kare) { *kare = yeni; degisti = true; } } // oynat modu: animf-yumuşak auto-advance (DeltaTime × hız) if (durum->oynat && sonKare > 0) { durum->_akis += ImGui::GetIO().DeltaTime * ImMax(durum->hiz, 0.1f); while (durum->_akis >= 1.0f) { durum->_akis -= 1.0f; if (*kare < sonKare) { (*kare)++; degisti = true; } else { durum->oynat = false; break; } // sonda dur } } const float h = animf(id, (hover || aktif || durum->oynat) ? 1.0f : 0.0f, 12.0f); ImDrawList* dl = ImGui::GetWindowDrawList(); // kare tik işaretleri (≤48 ise) — ray altında ince çentikler if (kareSayi <= 48 && kareSayi > 1) for (int i = 0; i < kareSayi; ++i) { const float x = ray0 + (ray1 - ray0) * (float)i / (float)sonKare; const bool ge = i <= *kare; dl->AddLine({x, cy + 8.0f}, {x, cy + 12.0f}, u32(ge ? t.vurgu : t.metinSoluk, ge ? 0.7f : 0.35f), 1.0f); } const float oran = sonKare > 0 ? (float)*kare / (float)sonKare : 0.0f; float headX = 0.0f; scrubberRay(dl, p, gen, cy, oran, ImMax(h, durum->oynat ? 1.0f : 0.0f), headX); // büyük kare HUD (oynat/hover/sürüklemede) char hud[48]; std::snprintf(hud, sizeof(hud), "Kare %d", *kare); degerHud(dl, {headX, cy}, hud, ImMax(h, aktif || durum->oynat ? 1.0f : 0.0f)); ImGui::PopID(); return degisti; } void renkBarLegend(const char* kimlik, float mn, float mx, const char* birim, int rampaTip) { const Tema& t = tema(); ImGui::PushID(kimlik); const float gen = ImMin(ImGui::GetContentRegionAvail().x, 220.0f); const float barY = 16.0f, yk = barY + 18.0f; const ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::Dummy({gen, yk}); ImDrawList* dl = ImGui::GetWindowDrawList(); const float x0 = p.x + 2.0f, x1 = p.x + gen - 2.0f; const float y0 = p.y, y1 = p.y + barY; // rampa: dikey dilimlerle çiz (gradient) const int adim = 48; for (int i = 0; i < adim; ++i) { const float a = x0 + (x1 - x0) * (float)i / (float)adim; const float b = x0 + (x1 - x0) * (float)(i + 1) / (float)adim; const ImVec4 c0 = rampaRenk(rampaTip, (float)i / (float)adim); const ImVec4 c1 = rampaRenk(rampaTip, (float)(i + 1) / (float)adim); const int vtx0 = dl->VtxBuffer.Size; dl->AddRectFilled({a, y0}, {b, y1}, u32(c0)); ImGui::ShadeVertsLinearColorGradientKeepAlpha(dl, vtx0, dl->VtxBuffer.Size, {a, y0}, {b, y0}, u32(c0), u32(c1)); } dl->AddRect({x0, y0}, {x1, y1}, u32(t.kenar, 0.9f), 2.0f, 0, 1.0f); // min / max etiketleri ImFont* f = ImGui::GetFont(); char buf[48]; std::snprintf(buf, sizeof(buf), birim && birim[0] ? "%.2f %s" : "%.2f", mn, birim ? birim : ""); dl->AddText(f, 11.0f, {x0, y1 + 3.0f}, u32(t.metinSoluk), buf); std::snprintf(buf, sizeof(buf), birim && birim[0] ? "%.2f %s" : "%.2f", mx, birim ? birim : ""); const ImVec2 mb = f->CalcTextSizeA(11.0f, FLT_MAX, 0.0f, buf); dl->AddText(f, 11.0f, {x1 - mb.x, y1 + 3.0f}, u32(t.metinSoluk), buf); // orta değer std::snprintf(buf, sizeof(buf), "%.2f", (mn + mx) * 0.5f); metniOrtala(dl, {(x0 + x1) * 0.5f, y1 + 8.5f}, 11.0f, u32(t.metinSoluk, 0.75f), buf); ImGui::PopID(); } } // namespace fiko::ui