#include "dinamik_komut_penceresi.hpp" #include #include #include #include #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/cekirdek/dinamik_komut.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/sahne/sahne_ref_secim.hpp" #include "fiko/ui/pencere_cerceve.hpp" #include "fiko/ui/tema.hpp" #include "imgui.h" namespace fiko { namespace { // Acik bir komut pencere ornegi (tek-atislik taslak durumu). unique_ptr ile heap'te // sabit adres → refSecim callback'i AcikKomut*'i guvenle yakalar (vektor realloc'suz). struct AcikKomut { std::string id; // DinamikKomut.id u32 sahip = 0; // refSecim sahip etiketi (sentetik) std::unordered_map sayilar; // doldurulmus sayisal degerler std::unordered_map metinler; // Metin tipi degerler std::string hata; // son calistir/dogrula hatasi bool ustte = false; // pencere "her zaman ustte" pin bool dolduruldu = false; // varsayilan degerler yazildi mi }; std::vector> g_acik; u32 g_sonrakiSahip = 0xD1000000u; // varlik kimlikleriyle (kucuk) cakismayan taban bool g_ustteVarsayilan = false; // yeni pencere "her zaman ustte" varsayilani (AyarSistemi) // Menu senkron durumu: registry surumu + eklenmis giris listesi (temizleme icin). u64 g_gorulenSurum = ~0ull; // ilk kare kesin senkron std::vector> g_eklenenMenu; // (grup, ad) f64 deger(const AcikKomut& a, const std::string& anahtar, f64 vars = 0.0) { auto it = a.sayilar.find(anahtar); return it == a.sayilar.end() ? vars : it->second; } // Tek parametre alanini ciz (feature_penceresi paramAlanlari kalibi, KomutParam kaynagi). void cizParam(AcikKomut& a, const KomutParam& p, SahneRefSecim& refSecim) { const ImVec4 CYAN = ui::tema().vurgu; const ImVec4 SOLUK = ui::tema().metinSoluk; const ImVec4 YESIL = ui::tema().basari; ImGui::PushID(p.anahtar.c_str()); const u32 sahip = a.sahip; if (p.tip == KomutParamTip::SahneNokta) { const std::string et = p.anahtar; const bool aktifBu = refSecim.aktifMi(sahip, et); if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); char btn[96]; std::snprintf(btn, sizeof(btn), "%s##%s", aktifBu ? "🎯 Yüze/noktaya tıkla…" : "🎯 Sahneden Nokta/Yüz Seç", p.anahtar.c_str()); if (ImGui::Button(btn, {-1, 0})) { AcikKomut* pa = &a; refSecim.baslat( sahip, et, [pa, anahtar = p.anahtar](const SahneRefSecim::Vurus& v) -> bool { pa->sayilar[anahtar + "x"] = v.nokta.x; pa->sayilar[anahtar + "y"] = v.nokta.y; pa->sayilar[anahtar + "z"] = v.nokta.z; pa->sayilar[anahtar + "Nx"] = v.normalVar ? v.normal.x : 0.0; pa->sayilar[anahtar + "Ny"] = v.normalVar ? v.normal.y : 0.0; pa->sayilar[anahtar + "Nz"] = v.normalVar ? v.normal.z : 0.0; pa->sayilar[anahtar + "Var"] = 1.0; return false; // tek tık → mod biter }, "Nokta/yüz için tıkla · ESC=bitir", /*beklenenTur*/ 1, /*serbestNokta*/ true); } if (aktifBu) ImGui::PopStyleColor(); if (aktifBu) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); else if (deger(a, p.anahtar + "Var") > 0.5) ImGui::TextColored(CYAN, "✔ %s: (%.1f, %.1f, %.1f)", p.etiket.c_str(), deger(a, p.anahtar + "x"), deger(a, p.anahtar + "y"), deger(a, p.anahtar + "z")); else ImGui::TextColored(SOLUK, "%s: seçilmedi", p.etiket.c_str()); } else if (p.tip == KomutParamTip::SahneEksen) { const std::string et = p.anahtar; const bool aktifBu = refSecim.aktifMi(sahip, et); if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); char btn[96]; std::snprintf(btn, sizeof(btn), "%s##%s", aktifBu ? "🎯 Kenara tıkla…" : "🎯 Sahneden Kenar Seç", p.anahtar.c_str()); if (ImGui::Button(btn, {-1, 0})) { AcikKomut* pa = &a; refSecim.baslat( sahip, et, [pa, anahtar = p.anahtar](const SahneRefSecim::Vurus& v) -> bool { if (v.alt == 0) return true; // kenar değil → modda kal pa->sayilar[anahtar + "G"] = (f64)v.govde; pa->sayilar[anahtar + "A"] = (f64)v.alt; return false; }, "Yön/eksen için kenara tıkla · ESC=bitir", /*beklenenTur*/ 2, /*serbestNokta*/ false); } if (aktifBu) ImGui::PopStyleColor(); if (aktifBu) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); else if (deger(a, p.anahtar + "G") > 0) ImGui::TextColored(CYAN, "✔ Kenar #%d", (int)deger(a, p.anahtar + "A")); else ImGui::TextColored(SOLUK, "%s: kenar seçilmedi", p.etiket.c_str()); } else if (p.tip == KomutParamTip::SahneGovde) { const std::string et = p.anahtar; const bool aktifBu = refSecim.aktifMi(sahip, et); if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); char btn[96]; std::snprintf(btn, sizeof(btn), "%s##%s", aktifBu ? "🎯 Gövdeye tıkla…" : "🎯 Sahneden Gövde Seç", p.anahtar.c_str()); if (ImGui::Button(btn, {-1, 0})) { AcikKomut* pa = &a; refSecim.baslat( sahip, et, [pa, anahtar = p.anahtar](const SahneRefSecim::Vurus& v) -> bool { if (v.govde == 0) return true; pa->sayilar[anahtar] = (f64)v.govde; return false; }, "Bir gövdeye tıkla · ESC=bitir", /*beklenenTur*/ 1, /*serbestNokta*/ false); } if (aktifBu) ImGui::PopStyleColor(); if (aktifBu) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); else if (deger(a, p.anahtar) > 0) ImGui::TextColored(CYAN, "✔ Gövde #%d", (int)deger(a, p.anahtar)); else ImGui::TextColored(SOLUK, "%s: gövde seçilmedi", p.etiket.c_str()); } else if (p.tip == KomutParamTip::Bayrak) { bool b = deger(a, p.anahtar) > 0.5; if (ImGui::Checkbox(p.etiket.c_str(), &b)) a.sayilar[p.anahtar] = b ? 1.0 : 0.0; } else if (p.tip == KomutParamTip::Secim) { int v = (int)deger(a, p.anahtar); std::vector ogeler; ogeler.reserve(p.secenekler.size()); for (const std::string& s : p.secenekler) ogeler.push_back(s.c_str()); if (!ogeler.empty() && ImGui::Combo(p.etiket.c_str(), &v, ogeler.data(), (int)ogeler.size())) a.sayilar[p.anahtar] = (f64)v; } else if (p.tip == KomutParamTip::Tamsayi) { int v = (int)deger(a, p.anahtar); if (ImGui::DragInt(p.etiket.c_str(), &v, (f32)p.adim, (int)p.minVeya, p.maksVeya > 0 ? (int)p.maksVeya : 0)) a.sayilar[p.anahtar] = (f64)v; } else if (p.tip == KomutParamTip::Metin) { char buf[256]; std::snprintf(buf, sizeof(buf), "%s", a.metinler[p.anahtar].c_str()); ImGui::SetNextItemWidth(-1); if (ImGui::InputText(p.etiket.c_str(), buf, sizeof(buf))) a.metinler[p.anahtar] = buf; } else { // Mesafe / Sayi char fmt[24]; std::snprintf(fmt, sizeof(fmt), "%%.3f%s%s", p.birim.empty() ? "" : " ", p.birim.c_str()); const f64 mn = p.minVeya, mx = p.maksVeya > 0 ? p.maksVeya : 0; f64 v = deger(a, p.anahtar); if (ImGui::DragScalar(p.etiket.c_str(), ImGuiDataType_Double, &v, (f32)p.adim, &mn, mx > 0 ? &mx : nullptr, fmt)) a.sayilar[p.anahtar] = v; } ImGui::PopID(); } // Bir komut penceresini ciz. return: bu ornek KAPANMALI mi (temizlik cagirana). bool pencereCiz(AcikKomut& a, Cekirdek& cekirdek, Sahne& sahne, SahneRefSecim& refSecim) { const ImVec4 SOLUK = ui::tema().metinSoluk; const ImVec4 HATA_RENK = ui::tema().hata; const DinamikKomut* kt = cekirdek.dinamikKomutlar().bul(a.id); if (!kt) return true; // komut kaldırıldı → pencere kapan char baslik[192]; std::snprintf(baslik, sizeof(baslik), "%s %s###dkomut_%u", kt->simge.empty() ? "◆" : kt->simge.c_str(), kt->ad.c_str(), a.sahip); bool pencereAcik = true; bool kapat = false; { ui::Pencere pen{baslik, &pencereAcik, {.boyut = {310, 340}, .pinDurum = &a.ustte}}; if (!pen) { return !pencereAcik; // katlanmış → RAII End(); kapanış X'i ile mi kapandı? } if (!kt->aciklama.empty()) ImGui::TextColored(SOLUK, "%s", kt->aciklama.c_str()); // ---- Parametreler (veri-odakli, grup basliklariyla) ---- const auto& d = a.sayilar; std::vector grupSira; for (const KomutParam& p : kt->parametreler) { if (!p.gorunur(d)) continue; if (std::find(grupSira.begin(), grupSira.end(), p.grup) == grupSira.end()) grupSira.push_back(p.grup); } for (const std::string& g : grupSira) { if (!g.empty() || grupSira.size() > 1) ImGui::SeparatorText(g.empty() ? "Parametreler" : g.c_str()); for (const KomutParam& p : kt->parametreler) { if (p.grup != g) continue; if (!p.gorunur(d)) continue; cizParam(a, p, refSecim); } } // ---- Dogrulama + hata satiri ---- std::string dogrulama; if (kt->dogrula) { KomutCalismaBaglam bg{cekirdek, sahne, a.sayilar, a.metinler}; dogrulama = kt->dogrula(bg); } if (!dogrulama.empty()) ImGui::TextColored(HATA_RENK, "⚠ %s", dogrulama.c_str()); else if (!a.hata.empty()) ImGui::TextColored(HATA_RENK, "⚠ %s", a.hata.c_str()); // ---- Alt eylem cubugu: ✔ Tamam / ✖ İptal ---- ImGui::Separator(); const bool onaylanabilir = dogrulama.empty(); if (!onaylanabilir) ImGui::BeginDisabled(); if (ImGui::Button("✔ Tamam", {-90, 0})) { a.hata.clear(); bool basarili = false; if (kt->calistir) { KomutCalismaBaglam bg{cekirdek, sahne, a.sayilar, a.metinler}; // Komut istisnasi uygulamayi cokertmez (Cekirdek::komutCalistir kalibi). try { basarili = kt->calistir(bg); } catch (const std::exception& e) { a.hata = e.what(); } catch (...) { a.hata = "bilinmeyen hata"; } } // Denetim/telemetri: dinamik komut da merkezi KomutCalisti olayindan gecsin. cekirdek.olaylar().yayinla( KomutCalisti{kt->ad.c_str(), kt->grup.c_str(), kt->kaynak == KomutKaynak::Lua ? "dinamik.lua" : "dinamik.eklenti", basarili}, kt->ad.c_str()); if (basarili) kapat = true; else if (a.hata.empty()) a.hata = "Komut başarısız (parametreleri kontrol edin)"; } if (!onaylanabilir) ImGui::EndDisabled(); ImGui::SameLine(); if (ImGui::Button("✖ İptal", {-1, 0})) kapat = true; } // Pencere kapanışı → RAII End() if (!pencereAcik) kapat = true; return kapat; } // Registry'deki bir komutu acan menu lambda'sini uretir. void menuGirisiEkle(Cekirdek& cekirdek, const DinamikKomut& k) { const std::string grup = k.grup.empty() ? "Eklenti" : k.grup; cekirdek.menuler().ekle( {grup, k.ad, k.simge.empty() ? "◆" : k.simge, 0, [id = k.id](Cekirdek&) { dinamikKomutAc(id); }, nullptr}); g_eklenenMenu.push_back({grup, k.ad}); } } // namespace void dinamikKomutMenuSenkron(Cekirdek& cekirdek) { DinamikKomutKaydi& reg = cekirdek.dinamikKomutlar(); if (reg.surum() == g_gorulenSurum) return; g_gorulenSurum = reg.surum(); // Onceden eklenen girisleri kaldir → tam tutarli yeniden kur. for (const auto& [grup, ad] : g_eklenenMenu) cekirdek.menuler().sil(grup, ad); g_eklenenMenu.clear(); for (const DinamikKomut& k : reg.hepsi()) menuGirisiEkle(cekirdek, k); } bool& dinamikKomutUstteVarsayilan() { return g_ustteVarsayilan; } void dinamikKomutAc(const std::string& id) { auto a = std::make_unique(); a->id = id; a->sahip = g_sonrakiSahip++; a->ustte = g_ustteVarsayilan; g_acik.push_back(std::move(a)); } void dinamikKomutPencereleriCiz(Cekirdek& cekirdek, Sahne& sahne, SahneRefSecim& refSecim) { // Yeni acilan pencereye varsayilan degerleri yaz (komut hala kayitliysa). for (auto& up : g_acik) { AcikKomut& a = *up; if (a.dolduruldu) continue; const DinamikKomut* kt = cekirdek.dinamikKomutlar().bul(a.id); if (!kt) continue; for (const KomutParam& p : kt->parametreler) { if (p.tip == KomutParamTip::Metin) a.metinler[p.anahtar] = p.metinVarsayilan; else if (p.tip != KomutParamTip::SahneNokta && p.tip != KomutParamTip::SahneEksen && p.tip != KomutParamTip::SahneGovde) a.sayilar[p.anahtar] = p.varsayilan; } a.dolduruldu = true; } for (auto it = g_acik.begin(); it != g_acik.end();) { AcikKomut& a = **it; if (pencereCiz(a, cekirdek, sahne, refSecim)) { if (refSecim.sahip() == a.sahip) refSecim.bitir(); it = g_acik.erase(it); } else { ++it; } } } } // namespace fiko