#include "gsd_penceresi.hpp" #include #include #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/gsd/gsd_feature.hpp" #include "fiko/gsd/gsd_registry.hpp" #include "fiko/gsd/gsd_sistemi.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/sahne/sahne_ref_secim.hpp" #include "fiko/ui/form.hpp" #include "fiko/ui/pencere_cerceve.hpp" #include "fiko/ui/tema.hpp" #include "imgui.h" namespace fiko { namespace { using gsd::FeatureParam; using gsd::FeatureTanim; using gsd::GsdFeature; using gsd::GsdSistemi; using parca::ParamTip; std::unordered_map g_gsdAcik; std::unordered_map g_gsdPin; // Görünür SahneNokta param tabanlarını (sıralı) topla — chained seçim için. std::vector gorunurNoktalar(const GsdFeature& feat, const FeatureTanim& td) { const auto& d = feat.parametreler(); std::vector baz; for (const FeatureParam& p : td.parametreler) { if (p.tip != ParamTip::SahneNokta) continue; if (p.gorunurMu && !p.gorunurMu(d)) continue; baz.push_back(p.anahtar); } return baz; } // Tek bir noktayı feature'a yaz (taban → x/y/z anahtar). gsdGuncelle → yeniden insa. void noktaYaz(GsdSistemi& sistem, GsdFeature& feat, const std::string& baz, const Vec3d& p) { sistem.gsdGuncelle(feat.kimlik(), baz + "x", p.x); sistem.gsdGuncelle(feat.kimlik(), baz + "y", p.y); sistem.gsdGuncelle(feat.kimlik(), baz + "z", p.z); } // Bir SahneNokta grubunu (baz) sahneden seç modunu başlat. sirali boş ise tekli // (bu baz), doluysa chained (baz'dan itibaren tüm görünür noktalar sırayla). void noktaSecBaslat(SahneRefSecim& refSecim, GsdSistemi& sistem, GsdFeature& feat, const std::string& baz, std::vector sirali, size_t basIdx) { const u32 fk = feat.kimlik(); const std::string etiket = "gsd_nokta_" + baz; // Chained kapanış: sirali[basIdx..] noktalarını tek tek doldur. auto durum = std::make_shared(basIdx); const size_t toplam = sirali.size(); refSecim.baslat( fk, etiket, [&sistem, fk, sirali, durum, toplam, &refSecim](const SahneRefSecim::Vurus& v) -> bool { GsdFeature* f = sistem.bul(fk); if (!f) return false; if (*durum >= toplam) return false; noktaYaz(sistem, *f, sirali[*durum], v.nokta); ++(*durum); if (*durum >= toplam) return false; // hepsi doldu → mod biter char h[96]; std::snprintf(h, sizeof(h), "%zu/%zu nokta seçildi · sıradaki: %s · ESC=bitir", *durum, toplam, sirali[*durum].c_str()); refSecim.hudAyarla(h); return true; // devam }, toplam > 1 ? std::string("1/") + std::to_string(toplam) + " nokta seç · ESC=bitir" : std::string(), /*beklenenTur*/ 0, /*serbestNoktaMi*/ true); (void)baz; } // Bir SahneNokta param alanı: 🎯 buton + 3 ince-ayar drag + aktiflik durumu. void sahneNoktaAlani(SahneRefSecim& refSecim, GsdSistemi& sistem, GsdFeature& feat, const FeatureParam& p, const FeatureTanim& td) { const ImVec4 CYAN = ui::tema().vurgu; const ImVec4 YESIL = ui::tema().basari; const std::string baz = p.anahtar; const std::string etiket = "gsd_nokta_" + baz; const bool aktifBu = refSecim.aktifMi(feat.kimlik(), etiket); const Vec3d cur{feat.p(baz + "x"), feat.p(baz + "y"), feat.p(baz + "z")}; ImGui::PushID(baz.c_str()); // 🎯 buton (aktifse yeşil vurgu) — bu noktadan itibaren sıralı seçim. if (aktifBu) ImGui::PushStyleColor(ImGuiCol_Button, {0.16f, 0.45f, 0.22f, 1.0f}); if (ImGui::Button(aktifBu ? "🎯 Seçiliyor…" : "🎯", {0, 0})) { // Bu baz'dan başlayarak görünür noktaları sırayla seç (2-nokta/spline zinciri). std::vector sirali = gorunurNoktalar(feat, td); size_t basIdx = 0; for (size_t i = 0; i < sirali.size(); ++i) if (sirali[i] == baz) { basIdx = i; break; } // Yalnız bu ve sonrasını zincirle (öncekiler zaten seçilmiş sayılır). std::vector kalan(sirali.begin() + (long)basIdx, sirali.end()); noktaSecBaslat(refSecim, sistem, feat, baz, kalan, 0); } if (aktifBu) ImGui::PopStyleColor(); ImGui::SameLine(); ImGui::TextColored(aktifBu ? YESIL : CYAN, "%s", p.etiket.c_str()); // İnce-ayar: X/Y/Z tek satır drag (dünya konumu; sahne tık üzerine yazar). f32 xyz[3] = {(f32)cur.x, (f32)cur.y, (f32)cur.z}; ImGui::SetNextItemWidth(-1); if (ImGui::DragFloat3("##xyz", xyz, 0.1f, 0, 0, "%.3f")) { sistem.gsdGuncelle(feat.kimlik(), baz + "x", (f64)xyz[0]); sistem.gsdGuncelle(feat.kimlik(), baz + "y", (f64)xyz[1]); sistem.gsdGuncelle(feat.kimlik(), baz + "z", (f64)xyz[2]); } ImGui::PopID(); } // Veri-odakli param alanlari (cok-modlu: Secim combo + kosullu gorunurluk). void paramAlanlari(SahneRefSecim& refSecim, GsdSistemi& sistem, GsdFeature& feat, const FeatureTanim& td) { const auto& parametreler = feat.parametreler(); // kosullu gorunurluk kaynagi for (const FeatureParam& p : td.parametreler) { if (p.gorunurMu && !p.gorunurMu(parametreler)) continue; // koşul saglanmadi if (p.tip == ParamTip::SahneNokta) { sahneNoktaAlani(refSecim, sistem, feat, p, td); continue; } const f64 mevcut = feat.p(p.anahtar); const std::string wid = "##" + p.anahtar; // kolon-hizalı alan() için gizli widget ID if (p.tip == ParamTip::Secim) { int idx = (int)(mevcut + 0.5); if (idx < 0 || idx >= (int)p.secenekler.size()) idx = 0; std::vector etiketler; etiketler.reserve(p.secenekler.size()); for (const std::string& s : p.secenekler) etiketler.push_back(s.c_str()); ui::alan(p.etiket.c_str()); if (ImGui::Combo(wid.c_str(), &idx, etiketler.data(), (int)etiketler.size())) sistem.gsdGuncelle(feat.kimlik(), p.anahtar, (f64)idx); } else if (p.tip == ParamTip::Bayrak) { bool b = mevcut > 0.5; if (ui::anahtarSatiri(p.etiket.c_str(), &b)) sistem.gsdGuncelle(feat.kimlik(), p.anahtar, b ? 1.0 : 0.0); } else if (p.tip == ParamTip::Tamsayi) { int v = (int)mevcut; ui::alan(p.etiket.c_str()); if (ImGui::DragInt(wid.c_str(), &v, (f32)p.adim, (int)p.minVeya, p.maksVeya > 0 ? (int)p.maksVeya : 0)) sistem.gsdGuncelle(feat.kimlik(), p.anahtar, (f64)v); } else { // Mesafe / Sayi f64 v = mevcut; 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; ui::alan(p.etiket.c_str()); if (ImGui::DragScalar(wid.c_str(), ImGuiDataType_Double, &v, (f32)p.adim, &mn, mx > 0 ? &mx : nullptr, fmt)) sistem.gsdGuncelle(feat.kimlik(), p.anahtar, v); } } } void gsdPenceresiCiz(Cekirdek& cekirdek, Sahne& sahne, GsdSistemi& sistem, GsdFeature& feat, SahneRefSecim& refSecim) { const ImVec4 CYAN = ui::tema().vurgu; const ImVec4 HATA_RENK = ui::tema().hata; const ImVec4 SOLUK = ui::tema().metinSoluk; const ImVec4 YESIL = ui::tema().basari; (void)cekirdek; const FeatureTanim* td = gsd::gsdTanimBul(feat.tip()); if (!td) return; const bool tel = gsd::gsdTelMi(*td); bool& ustte = g_gsdPin[feat.kimlik()]; char baslik[192]; std::snprintf(baslik, sizeof(baslik), "%s %s###gsd_%u", td->simge.c_str(), feat.ad().c_str(), feat.kimlik()); bool acik = true, erken = false; { ui::Pencere p{baslik, &acik, {.boyut = {300, 0}, .pinDurum = &ustte}}; if (p) { // Ad (inline duzenlenebilir) { char buf[96]; std::snprintf(buf, sizeof(buf), "%s", feat.ad().c_str()); ImGui::SetNextItemWidth(-1); if (ImGui::InputText("##ad", buf, sizeof(buf))) feat.adAyarla(buf); } ImGui::TextColored(SOLUK, "%s", tel ? "Tel-Kafes (gerçek B-Rep kenar)" : "Açık Yüzey (Shell)"); // Yuzey feature'lari icin profil bilgisi if (!tel) { ImGui::SeparatorText("Profil"); if (feat.sketch() != 0) ImGui::TextColored(CYAN, "✎ Aktif sketch profili"); else ImGui::TextColored(HATA_RENK, "Sketch profili yok"); } // Tel-kafes: sahneden-seçim ipucu (elle XYZ yalnız ince ayar). if (tel) { const bool bizeAit = refSecim.aktif() && refSecim.sahip() == feat.kimlik(); if (bizeAit) ImGui::TextColored(YESIL, "● %s", refSecim.hudMetin()); else ImGui::TextColored(SOLUK, "🎯 ile sahneden tıkla-seç · XYZ ince ayar"); } ImGui::SeparatorText("Parametreler"); paramAlanlari(refSecim, sistem, feat, *td); if (!feat.hata().empty()) { ImGui::Spacing(); ui::bilgiSeridi(3, feat.hata().c_str()); } ImGui::Separator(); const bool onaylanabilir = feat.hata().empty(); if (!onaylanabilir) ImGui::BeginDisabled(); if (ImGui::Button("✔ Tamam", {-90, 0})) { if (sistem.gsdOnayla(feat.kimlik())) { if (refSecim.sahip() == feat.kimlik()) refSecim.bitir(); g_gsdAcik[feat.kimlik()] = false; } } if (!onaylanabilir) ImGui::EndDisabled(); ImGui::SameLine(); if (ImGui::Button("✖ İptal", {-1, 0})) { const u32 k = feat.kimlik(); if (refSecim.sahip() == k) refSecim.bitir(); sistem.gsdIptal(k); g_gsdAcik[k] = false; erken = true; } } } if (!erken && !acik) { if (refSecim.sahip() == feat.kimlik()) refSecim.bitir(); g_gsdAcik[feat.kimlik()] = false; } (void)sahne; } } // namespace void gsdPencereAc(u32 kimlik) { g_gsdAcik[kimlik] = true; } void gsdPencereleriCiz(Cekirdek& cekirdek, Sahne& sahne, GsdSistemi& sistem, SahneRefSecim& refSecim) { for (auto it = g_gsdAcik.begin(); it != g_gsdAcik.end();) { if (!it->second) { it = g_gsdAcik.erase(it); continue; } GsdFeature* feat = sistem.bul(it->first); if (!feat) { // feature gitti → ona ait seçim modunu da kapat if (refSecim.sahip() == it->first) refSecim.bitir(); it = g_gsdAcik.erase(it); continue; } gsdPenceresiCiz(cekirdek, sahne, sistem, *feat, refSecim); ++it; } } } // namespace fiko