#include "baglam_menu.hpp" #include #include #include #include #include "fiko/baglam/baglam_hedef.hpp" // baglam::regAyristir #include "fiko/cekirdek/cekirdek.hpp" // Cekirdek, MenuOge, menuler/komutCalistir/uygula #include "fiko/girdi/baglam_politika.hpp" // girdi::PolitikaKarar / MenuOgeSecim #include "fiko/render/orbit_kamera.hpp" // OrbitKamera #include "fiko/sahne/sahne.hpp" // Sahne, Dugum #include "fiko/sahne/sahne_islem.hpp" // SilIslem #include "fiko/ui/animasyon.hpp" // ui::animf / animSifirla (bant mikro-animasyonları) #include "fiko/ui/arac_halkasi.hpp" // ui::AracOge / aracHalkasi / AracDizilim #include "fiko/ui/bilesen.hpp" // ui::ikonButon / neonAyrac / glowCerceve #include "fiko/ui/bilesen_ek.hpp" // ui::toastGoster (KYA "ada göre seç" geri bildirimi) #include "fiko/ui/simge.hpp" // ui::Simge #include "fiko/ui/tema.hpp" // ui::tema / karisim / u32 #include "hizli3d_penceresi.hpp" // HizliUIDurum #include "lisans_yukle.hpp" // lisansSistemi (salt-okunur kip) #include "imgui.h" #include "uygulama_baglam.hpp" namespace fiko { namespace { // Renk/alfa sürükleme oturumları (undo tabanı): radyal toolbar ve DM arama menüsü bandı aynı // durumu paylaşır (aynı anda tek menü açık). Menü oturum ortasında kapanırsa kesinleştirme // grafikOzellikOturumTamamla ile veya bir sonraki çizimde yapılır. bool s_renkOturum = false; std::vector> s_renkTaban; f64 s_renkSonYenile = 0.0; bool s_alfaOturum = false; std::vector> s_alfaTaban; char s_kyaSec[96] = ""; // Seçimden boyanacak yüz grupları: yüz kipi → seçili yüz ordinalleri; gövde kipi → // seçili gövdelerin TÜM yüzleri (grup rengi çoklu-seçim). std::vector>> renkGrupCikar(Sahne& sahne) { std::vector>> renkGrup; if (sahne.kip() == SecimKip::Yuz) { for (const SecimOge& o : sahne.secililer()) { if (o.alt == 0) continue; Dugum* dg = sahne.bul(o.govde); if (!dg || dg->yuzSayi_ == 0) continue; // datum/mesh'siz düğüm: renk editörü işlevsiz auto it = std::find_if(renkGrup.begin(), renkGrup.end(), [&](const auto& g) { return g.first == o.govde; }); if (it == renkGrup.end()) renkGrup.push_back({o.govde, {o.alt}}); else it->second.push_back(o.alt); } } else { // gövde kipi: her seçili gövdenin tüm yüz ordinalleri (1..yuzSayi_) for (const SecimOge& o : sahne.secililer()) { Dugum* d = sahne.bul(o.govde); if (!d || d->yuzSayi_ == 0) continue; std::vector hepsi; hepsi.reserve(d->yuzSayi_); for (u32 y = 1; y <= d->yuzSayi_; ++y) hepsi.push_back(y); renkGrup.push_back({o.govde, std::move(hepsi)}); } } return renkGrup; } // Ucuz varlık kontrolü (grup kurmadan — grafikOzellikYuk her kare çağrılabilir). bool renkGrupVarMi(Sahne& sahne) { if (sahne.kip() == SecimKip::Yuz) { for (const SecimOge& o : sahne.secililer()) if (o.alt != 0) if (Dugum* dg = sahne.bul(o.govde); dg && dg->yuzSayi_ > 0) return true; return false; } for (const SecimOge& o : sahne.secililer()) if (Dugum* d = sahne.bul(o.govde); d && d->yuzSayi_ > 0) return true; return false; } // ---- Bant görsel bileşenleri (arama menüsü/aeroglass diliyle: hover büyüme + glow) ---- // Sabitler grafikOzellikYuk hesabıyla BİREBİR eşleşmeli. constexpr float CIP_YUK = 21.0f; // KYA kimlik çipi yüksekliği constexpr float RENK_HIT = 24.0f; // renk swatch/palet satırı hit yüksekliği // Yuvarlak renk dairesi: hover'da büyür + cyan glow; aktifHalka → çevresinde kalıcı vurgu // halkası (mevcut renk göstergesi). hit: dikey hizalama için sabit vuruş alanı. bool renkDaire(const char* kimlik, const Vec3f& c, float yaricap, bool aktifHalka) { const ui::Tema& t = ui::tema(); const ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::InvisibleButton(kimlik, {yaricap * 2.0f + 6.0f, RENK_HIT}); const ImGuiID id = ImGui::GetItemID(); const bool hov = ImGui::IsItemHovered(); const float h = ui::animf(id, hov ? 1.0f : 0.0f, 16.0f); ImDrawList* dl = ImGui::GetWindowDrawList(); const ImVec2 m{p.x + yaricap + 3.0f, p.y + RENK_HIT * 0.5f}; const float r = yaricap + 1.5f * h; if (h > 0.01f) dl->AddCircleFilled(m, r + 3.5f, ui::u32(t.vurgu, 0.22f * h)); // hover glow dl->AddCircleFilled(m, r, ImGui::ColorConvertFloat4ToU32({c.x, c.y, c.z, 1.0f})); if (aktifHalka) dl->AddCircle(m, r + 2.0f, ui::u32(t.vurgu, 0.85f), 0, 1.6f); else dl->AddCircle(m, r, ui::u32(t.metin, 0.22f + 0.55f * h), 0, 1.0f); return ImGui::IsItemClicked(); } // Alfa gradyan barı: soldan şeffaf → tam renk; yuvarlak tutamaç sürüklenir. degisti döner; // birakti → sürükleme bu kare bitti (undo commit noktası). bool alfaBar(const char* kimlik, f32* alfa, const Vec3f& c, float genislik, float yukseklik, bool& birakti) { const ui::Tema& t = ui::tema(); const ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::InvisibleButton(kimlik, {genislik, yukseklik}); const ImGuiID id = ImGui::GetItemID(); const bool aktif = ImGui::IsItemActive(); const bool hov = ImGui::IsItemHovered(); birakti = ImGui::IsItemDeactivated(); const float bx0 = p.x + 8.0f, bx1 = p.x + genislik - 8.0f; bool degisti = false; if (aktif) { const float yeni = std::clamp((ImGui::GetIO().MousePos.x - bx0) / std::max(bx1 - bx0, 1.0f), 0.0f, 1.0f); if (yeni != *alfa) { *alfa = yeni; degisti = true; } } const float h = ui::animf(id, (hov || aktif) ? 1.0f : 0.0f, 14.0f); ImDrawList* dl = ImGui::GetWindowDrawList(); const float by = p.y + yukseklik * 0.5f; const float bh = 3.5f + 1.0f * h; // bar yarı-kalınlığı (hover'da hafif kalınlaşır) const ImU32 renkTam = ImGui::ColorConvertFloat4ToU32({c.x, c.y, c.z, 1.0f}); const ImU32 renkSaydam = ImGui::ColorConvertFloat4ToU32({c.x, c.y, c.z, 0.05f}); dl->AddRectFilled({bx0 - 1.0f, by - bh - 1.0f}, {bx1 + 1.0f, by + bh + 1.0f}, ui::u32(t.cerceve, 0.95f), bh + 1.0f); // zemin dl->AddRectFilledMultiColor({bx0, by - bh}, {bx1, by + bh}, renkSaydam, renkTam, renkTam, renkSaydam); // alfa önizleme gradyanı dl->AddRect({bx0 - 1.0f, by - bh - 1.0f}, {bx1 + 1.0f, by + bh + 1.0f}, ui::u32(t.vurgu, 0.20f + 0.35f * h), bh + 1.0f, 0, 1.0f); const float tx = bx0 + (*alfa) * (bx1 - bx0); // tutamaç if (h > 0.01f) dl->AddCircleFilled({tx, by}, 8.5f + 1.5f * h, ui::u32(t.vurgu, 0.22f * h)); dl->AddCircleFilled({tx, by}, 5.5f + 1.0f * h, ui::u32(t.metin, 1.0f)); dl->AddCircle({tx, by}, 5.5f + 1.0f * h, ui::u32(t.vurgu, 0.55f + 0.45f * h), 0, 1.6f); if (hov) ImGui::SetTooltip("Saydamlık: %%%d", (int)(*alfa * 100.0f + 0.5f)); return degisti; } // KYA kimlik çipi (pill): tıkla → kopyala. Hover'da cyan, kopyalanınca yeşil parlar. // maksGen > 0 → çip o genişliğe kırpılır (uzun gövde adı bandı taşırmasın); tooltip tam metin. bool kimlikCip(const char* metin, float maksGen) { const ui::Tema& t = ui::tema(); const ImVec2 mb = ImGui::CalcTextSize(metin); float gen = mb.x + 18.0f; if (maksGen > 0.0f && gen > maksGen) gen = maksGen; const ImVec2 min = ImGui::GetCursorScreenPos(); const ImVec2 max{min.x + gen, min.y + CIP_YUK}; ImGui::InvisibleButton("##kyaCip", {gen, CIP_YUK}); const bool hov = ImGui::IsItemHovered(); const bool tik = ImGui::IsItemClicked(); const float hv = ui::animf(ImGui::GetItemID(), hov ? 1.0f : 0.0f, 14.0f); const ImGuiID fid = ImGui::GetID("##kyaCipFlash"); // kopyalama flaşı (yeşil sönümlenir) if (tik) ui::animSifirla(fid, 1.0f); const float fl = ui::animf(fid, 0.0f, 3.0f); ImDrawList* dl = ImGui::GetWindowDrawList(); const float r = CIP_YUK * 0.5f; const float parla = std::max(hv, fl); if (parla > 0.01f) ui::glowCerceve(dl, min, max, fl > hv ? t.basari : t.vurgu, r, 0.5f * parla); dl->AddRectFilled(min, max, ui::u32(ui::karisim(t.panel, t.vurgu, 0.10f + 0.10f * hv), 1.0f), r); dl->AddRect(min, max, ui::u32(ui::karisim(t.vurgu, t.basari, fl), 0.40f + 0.50f * parla), r, 0, 1.2f); const ImVec4 kirp{min.x, min.y, max.x - 7.0f, max.y}; // metin çip içinde kırpılır dl->AddText(ImGui::GetFont(), ImGui::GetFontSize(), {min.x + 9.0f, min.y + (CIP_YUK - mb.y) * 0.5f}, ui::u32(t.metin, 0.92f), metin, nullptr, 0.0f, &kirp); if (hov) ImGui::SetTooltip("%s — kopyala", metin); return tik; } // KYA "ada göre seç" başarıyla seçimi sıçrattı (kip/seçim değişti) — kompakt bant bunu // menüyü kapatmak için okur (içerik/komut listesi bayatladı). Oku-ve-temizle. bool s_kyaSecimSicradi = false; // KYA kalıcı kimlik satırı (kimlik çipi + ada göre seç) — ayar kapalıysa hiçbir şey çizmez. // kompakt → arama bandı: çip ve kutu alt alta, kutu tam genişlik; radyal → yan yana. void kyaSatirCiz(UygulamaBaglam& b, bool kompakt) { Sahne& sahne = b.sahne; if (!geometri::kaliciKimlikAcikMi()) return; const ui::Tema& t = ui::tema(); std::string kyaAd; if (sahne.secililer().size() == 1 && sahne.secililer()[0].alt != 0) kyaAd = sahne.kimlikMetni(sahne.secililer()[0]); if (!kyaAd.empty()) { const float cipMaks = kompakt ? std::max(ImGui::GetContentRegionAvail().x - 8.0f, 90.0f) : 0.0f; if (kimlikCip(("🏷 " + kyaAd).c_str(), cipMaks)) { ImGui::SetClipboardText(kyaAd.c_str()); ui::toastGoster("Kalıcı kimlik kopyalandı", ui::ToastTip::Bilgi); } if (!kompakt) ImGui::SameLine(0.0f, 8.0f); } ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f); ImGui::PushStyleColor(ImGuiCol_FrameBg, ui::u32(ui::karisim(t.cerceve, t.vurgu, 0.07f), 1.0f)); ImGui::SetNextItemWidth(kompakt ? std::max(ImGui::GetContentRegionAvail().x - 8.0f, 120.0f) : 150.0f); if (ImGui::InputTextWithHint("##kyaSec", "🔎 ada göre seç (F7/E3/V5)", s_kyaSec, sizeof(s_kyaSec), ImGuiInputTextFlags_EnterReturnsTrue)) { if (sahne.kimlikMetniSec(s_kyaSec)) { s_kyaSec[0] = 0; b.secimiSigdir(); // bulunan öğeyi çerçevele (ekran dışı/gizli olabilir — "git/bul" davranışı) if (kompakt) s_kyaSecimSicradi = true; // bant: seçim/kip değişti → menü bayat, kapat } else ui::toastGoster("Kalıcı kimlik bulunamadı", ui::ToastTip::Uyari); } ImGui::PopStyleColor(); ImGui::PopStyleVar(); } } // namespace bool grafikOzellikSecimSicradi() { const bool v = s_kyaSecimSicradi; s_kyaSecimSicradi = false; return v; } float grafikOzellikYuk(Sahne& sahne) { const bool yuzKip = sahne.kip() == SecimKip::Yuz; const bool govdeKip = sahne.kip() == SecimKip::Govde; const bool kenarNokta = sahne.kip() == SecimKip::Kenar || sahne.kip() == SecimKip::Nokta; const bool renkVar = (yuzKip || govdeKip) && renkGrupVarMi(sahne); const bool kyaVar = geometri::kaliciKimlikAcikMi() && (renkVar || (kenarNokta && !sahne.secililer().empty())); if (!renkVar && !kyaVar) return 0.0f; const float fh = ImGui::GetFrameHeight(); const float sy = ImGui::GetStyle().ItemSpacing.y; float y = 4.0f; if (kyaVar) { // Çip satırı yalnız kimlik metni GERÇEKTEN doluysa (KID'siz öğede kyaSatirCiz çizmez; // koşulsuz saymak bantta boş şerit bırakırdı). if (sahne.secililer().size() == 1 && sahne.secililer()[0].alt != 0 && !sahne.kimlikMetni(sahne.secililer()[0]).empty()) y += CIP_YUK + sy; // kimlik çipi satırı y += fh + sy; // ada göre seç kutusu } if (renkVar) { if (kyaVar) y += 7.0f + sy; // neon ayraç y += RENK_HIT + sy; // renk swatch + palet daireleri satırı y += (fh + 6.0f) + sy; // alfa barı + ikon butonlar satırı (ikonButon karesi) } return y + 2.0f; } bool grafikOzellikSatiriCiz(UygulamaBaglam& b, bool kompakt) { // Salt-okunur (lisanssız görüntüleyici): bant HİÇ çizilmez. Buradaki renk/alfa // sürüklemesi ÖNCE sahneyi boyayıp SONRA undo kaydı iter (post-hoc DuzenleIslem); // kaydı kapıda reddetmek boyamayı geri almaz → tutarsızlık. Kaynağında kesiyoruz. if (lisansSistemi().saltOkunur()) return false; Sahne& sahne = b.sahne; Cekirdek& cekirdek = b.cekirdek; const bool yuzKip = sahne.kip() == SecimKip::Yuz; const bool govdeKip = sahne.kip() == SecimKip::Govde; if (!yuzKip && !govdeKip) { // kenar/nokta: şimdilik yalnız KYA satırı (renk render'a baked değil) const bool kenarNokta = sahne.kip() == SecimKip::Kenar || sahne.kip() == SecimKip::Nokta; if (!kenarNokta || !geometri::kaliciKimlikAcikMi() || sahne.secililer().empty()) return false; kyaSatirCiz(b, kompakt); return true; } auto renkGrup = renkGrupCikar(sahne); // gövde → boyanacak yüz ordinalleri if (renkGrup.empty()) return false; // KYA kalıcı kimlik satırı (kimlik çipi + ada göre seç) — ayar açıkken çizer. if (geometri::kaliciKimlikAcikMi()) { kyaSatirCiz(b, kompakt); ui::neonAyrac(); } Vec3f ilkRenk{0.55f, 0.65f, 0.8f}; if (Dugum* d0 = sahne.bul(renkGrup[0].first)) ilkRenk = d0->yuzOzellik(renkGrup[0].second[0]).renk; // salt-okuma (override kirletmez) f32 renk[3] = {ilkRenk.x, ilkRenk.y, ilkRenk.z}; // Mevcut renk: halkalı büyük daire → tıkla: hue-wheel renk seçici popup'ı. if (renkDaire("##yuzRenkSwatch", ilkRenk, 9.0f, true)) ImGui::OpenPopup("##fkRenkSecici"); if (ImGui::IsItemHovered()) ImGui::SetTooltip(yuzKip ? "Seçili yüz(ler)in rengi — tıkla: renk seçici" : "Seçili gövde(ler)in rengi — tıkla: renk seçici"); bool renkDegisti = false; bool pickerAcik = false; ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 10.0f); if (ImGui::BeginPopup("##fkRenkSecici")) { pickerAcik = true; ImGui::SetNextItemWidth(168.0f); renkDegisti = ImGui::ColorPicker3( "##fkPicker", renk, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel); // NavEnableKeyboard kapalı → ImGui popup'ı Esc ile kendisi kapatmaz; elle kapat // (ilk Esc seçiciyi, ikincisi menüyü kapatır). if (ImGui::IsKeyPressed(ImGuiKey_Escape)) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } ImGui::PopStyleVar(); if (renkDegisti) { if (!s_renkOturum) { // oturum tabanı: etkilenen her gövdenin anlik'ı (undo) s_renkTaban.clear(); for (auto& [gk, yy] : renkGrup) { (void)yy; s_renkTaban.push_back({gk, sahne.anlik(gk)}); } s_renkOturum = true; } const Vec3f yeni{renk[0], renk[1], renk[2]}; const f64 t = ImGui::GetTime(); const bool yenile = (t - s_renkSonYenile > 0.08); for (auto& [gk, yuzler] : renkGrup) if (Dugum* d = sahne.bul(gk)) { for (u32 y : yuzler) d->yuzOzellikYaz(y).renk = yeni; if (yenile) sahne.ogeRenkYenile(*d); } if (yenile) s_renkSonYenile = t; } if (s_renkOturum && !renkDegisti && !pickerAcik) { // seçici kapandı → kesin + undo (tek adım) for (auto& [gk, taban] : s_renkTaban) if (Dugum* d = sahne.bul(gk)) { sahne.ogeRenkYenile(*d); // kesin son hal (tam re-upload) cekirdek.uygula(std::make_unique(sahne, taban, sahne.anlik(gk))); } s_renkOturum = false; } // Yüz alanına anlık-commit uygula (preset/sıfırla): tek adımda gövde-başı DuzenleIslem undo. const auto commitUygula = [&](auto yaz) { for (auto& [gk, yuzler] : renkGrup) if (Dugum* d = sahne.bul(gk)) { const DugumPusula taban = sahne.anlik(gk); for (u32 y : yuzler) yaz(*d, y); sahne.ogeRenkYenile(*d); cekirdek.uygula(std::make_unique(sahne, taban, sahne.anlik(gk))); } }; // Hızlı renk paleti (yaygın CAD renkleri) — swatch'a tıkla=anında uygula. static const Vec3f palet[] = { {0.85f, 0.22f, 0.22f}, {0.95f, 0.55f, 0.15f}, {0.93f, 0.83f, 0.22f}, {0.32f, 0.72f, 0.34f}, {0.20f, 0.55f, 0.90f}, {0.55f, 0.35f, 0.85f}, {0.55f, 0.65f, 0.80f}, {0.24f, 0.25f, 0.28f}, {0.92f, 0.92f, 0.92f}}; for (int i = 0; i < (int)IM_ARRAYSIZE(palet); ++i) { const Vec3f c = palet[i]; ImGui::SameLine(0.0f, i == 0 ? 5.0f : 0.0f); ImGui::PushID(2000 + i); if (renkDaire("##pal", c, 7.0f, false)) commitUygula([&](Dugum& d, u32 y) { d.yuzOzellikYaz(y).renk = c; }); ImGui::PopID(); } // Alfa (saydamlık) gradyan barı — sürükleme oturumu + bırakışta undo. f32 alfa = 1.0f; if (Dugum* d0 = sahne.bul(renkGrup[0].first)) alfa = d0->yuzOzellik(renkGrup[0].second[0]).alfa; if (!kompakt) ImGui::SameLine(0.0f, 10.0f); // kompakt: alfa/göz/sıfırla ikinci satıra iner const float ikonYuk = ImGui::GetFrameHeight() + 6.0f; // ikonButon karesiyle hizalı satır bool alfaBirakti = false; if (alfaBar("##alfaBar", &alfa, {renk[0], renk[1], renk[2]}, kompakt ? 118.0f : 110.0f, ikonYuk, alfaBirakti)) { if (!s_alfaOturum) { s_alfaTaban.clear(); for (auto& [gk, yy] : renkGrup) { (void)yy; s_alfaTaban.push_back({gk, sahne.anlik(gk)}); } s_alfaOturum = true; } for (auto& [gk, yuzler] : renkGrup) if (Dugum* d = sahne.bul(gk)) { for (u32 y : yuzler) d->yuzOzellikYaz(y).alfa = alfa; sahne.ogeRenkYenile(*d); } } if (s_alfaOturum && alfaBirakti) { for (auto& [gk, taban] : s_alfaTaban) if (Dugum* d = sahne.bul(gk)) { sahne.ogeRenkYenile(*d); cekirdek.uygula(std::make_unique(sahne, taban, sahne.anlik(gk))); } s_alfaOturum = false; } // Görünür/Gizle — seçili yüzleri gizle/göster (içini gör). İlk yüzün durumuna göre topluca ters çevir. bool ilkGorunur = true; if (Dugum* dg = sahne.bul(renkGrup[0].first)) ilkGorunur = dg->yuzOzellik(renkGrup[0].second[0]).gorunur; ImGui::SameLine(0.0f, 6.0f); if (ui::ikonButon(ilkGorunur ? "👁" : "🚫", ilkGorunur ? "Seçili yüzleri gizle" : "Seçili yüzleri göster")) commitUygula([&](Dugum& d, u32 y) { d.yuzOzellikYaz(y).gorunur = !ilkGorunur; }); // Varsayılana dön — yüz renk/alfa override'ını kaldır (taban/STEP rengine). ImGui::SameLine(0.0f, 6.0f); if (ui::ikonButon("⟲", "Varsayılana dön (rengi sıfırla)")) commitUygula([](Dugum& d, u32 y) { d.yuzOz.erase(y); }); return true; } void grafikOzellikOturumTamamla(UygulamaBaglam& b) { if (s_renkOturum) { for (auto& [gk, taban] : s_renkTaban) if (Dugum* d = b.sahne.bul(gk)) { b.sahne.ogeRenkYenile(*d); b.cekirdek.uygula(std::make_unique(b.sahne, taban, b.sahne.anlik(gk))); } s_renkOturum = false; } if (s_alfaOturum) { for (auto& [gk, taban] : s_alfaTaban) if (Dugum* d = b.sahne.bul(gk)) { b.sahne.ogeRenkYenile(*d); b.cekirdek.uygula(std::make_unique(b.sahne, taban, b.sahne.anlik(gk))); } s_alfaOturum = false; } } void baglamPolitikaMenuCiz(UygulamaBaglam& b, ImGuiIO& io, girdi::PolitikaKarar& sonPolitika, u32 sonPolitikaHedef, ImVec2 sonPolitikaKonum, HizliUIDurum& hizliDurum, bool& panelSketch) { if (!sonPolitika.gecerli()) return; Cekirdek& cekirdek = b.cekirdek; Sahne& sahne = b.sahne; OrbitKamera& kamera = b.kamera; auto& gorunurDegistir = b.gorunurDegistir; u32& hizli3dKimlik = hizliDurum.hizli3dKimlik; bool& hizli3dAcik = hizliDurum.hizli3dAcik; // ---- Grafik özellik toolbar'ı: seçime göre KYA + renk/alfa/görünürlük — radyal menünün // ÜSTÜNDE. İçerik grafikOzellikSatiriCiz'de (DM arama menüsü üst bandıyla TEK kaynak). ---- if (grafikOzellikYuk(sahne) > 0.0f) { ImGui::SetNextWindowPos({sonPolitikaKonum.x - 4.0f, sonPolitikaKonum.y - 40.0f}, ImGuiCond_Always); ImGui::SetNextWindowBgAlpha(0.94f); ImGui::Begin("##grafikOzellikToolbar", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing); grafikOzellikSatiriCiz(b, false); ImGui::End(); } // Kimlik → registry (grup, ad) eşlemesi (merkezi tek tanım). // İKİ format: (1) motor önerileri regKimlik("grup\x1fad") — doğrudan çözülür; // (2) BaglamPolitika kısa kimliği ("fillet"...) — harita ile çözülür (fallback). const auto komutBul = [&](const std::string& kimlik) -> const MenuOge* { std::string rgGrup, rgAd; if (baglam::regAyristir(kimlik, rgGrup, rgAd)) { // motor kaynaklı registry kimliği for (const MenuOge& o : cekirdek.menuler().hepsi()) if (o.grup == rgGrup && o.ad == rgAd) return &o; return nullptr; } struct Esle { const char* kimlik; const char* grup; const char* ad; }; static const Esle harita[] = { {"fillet", "İşlem", "Kenar Yuvarlat (3B)"}, {"chamfer", "İşlem", "Pah (3B)"}, {"kenar_eg", "Değiştir", "Kenardan Eğ"}, // kenar menteşe → komşu yüz eğilir (Fikri) {"kenar_uzat", "Değiştir", "Kenardan Uzat"}, // komşu düz yüz itilir → kenar uzar {"yuz_itcek", "Değiştir", "Yüz İt/Çek"}, // radyal menü → numeric push/pull {"yuz_kaldir", "Değiştir", "Yüz Kaldır"}, // radyal menü → Remove Face {"kesit", "Değiştir", "Kesit"}, // radyal menü → Split (düzlemle böl) {"olc", "Ölçüm", "Ölçüm Penceresi (M)"}, {"pocket", "Feature", "Pocket (Cep)"}, {"sketch_yuz", "Sketch", "Sketch Oluştur"}, {"sil", "Düzenle", "Seçileni Sil"}, // Akıllı seçim alt-halkası (radyal "Seçim" 🎯) → registry "Seçim" komutları // (belge_penceresi kAs kayıtları; adlar emoji önekli — birebir eşleşmeli). {"sec_teget", "Seçim", "⌾ Teğet yüzleri seç (fillet zinciri)"}, {"sec_koplanar", "Seçim", "▱ Koplanar yüzleri seç"}, {"sec_paralel", "Seçim", "∥ Paralel yüzleri seç"}, {"sec_benzer", "Seçim", "⊘ Aynı ölçüdeki yüzleri seç (bu çaptaki delikler)"}, {"sec_ayni_renk", "Seçim", "🎨 Aynı renkli yüzleri seç"}, {"sec_zincir", "Seçim", "◠ Teğet kenar zincirini seç (loop)"}, {"sec_benzer_kenar", "Seçim", "◯ Aynı ölçüdeki kenarları seç (bu R'deki filletler)"}, // Montaj Kısıtları alt-halkası (radyal "Montaj Kısıtları" 🔗) → registry // "Montaj" komutları (belge_penceresi.cpp montajKisitUygula kayıtları). {"montaj_sabit", "Montaj", "Sabit"}, {"montaj_es_eksenli", "Montaj", "Eş Eksenli"}, {"montaj_cakisik", "Montaj", "Çakışık"}, {"montaj_mesafe", "Montaj", "Mesafe"}, {"montaj_aci", "Montaj", "Açı"}, // Gövde sağ-tık → Keskin Kenar analizi (panelde pah/fillet önerisi çipleri). {"keskin_analiz", "Analiz", "Keskin Kenar"}, // Gövde sağ-tık → Zekâ Analizi (Geometri Zekâ Motoru feature tanıma özeti). {"zeka_analiz", "Analiz", "Zekâ Analizi"}, {"cizgi", "Çizim", "Çizgi"}, {"cember", "Çizim", "Daire"}, {"dikdortgen", "Çizim", "Dikdörtgen"}, {"kutu_ekle", "Geometri", "Kutu"}, {"silindir_ekle", "Geometri", "Silindir"}, {"tumunu_sigdir", "Görünüm", "Tümünü Sığdır"}, {"gorunum", "Görünüm", "İzometrik"}, }; const char* grup = nullptr; const char* ad = nullptr; for (const auto& e : harita) if (kimlik == e.kimlik) { grup = e.grup; ad = e.ad; break; } if (!grup) return nullptr; // gizle/cam_kontur/kopya/duzenle/kisit → pasif for (const MenuOge& o : cekirdek.menuler().hepsi()) if (o.grup == grup && o.ad == ad) return &o; return nullptr; }; // Hedef gövdeye doğrudan uygulanan inline eylemler (registry'de komut yok). const auto inlineKimlikMi = [](const std::string& k) { return k == "sec" || k == "yakinlas" || k == "agirlik" || k == "gizle" || k == "sil" || k == "kisit"; }; // Bir öğenin main-inline/registry ile çalıştırılabilir olup olmadığı. const auto ogeEtkin = [&](const girdi::MenuOgeSecim& s) { return s.etkin && (inlineKimlikMi(s.komutKimlik) || komutBul(s.komutKimlik) != nullptr); }; // Inline eylem → sanal MenuOge ile MERKEZİ dispatch (komutCalistir). Registry'e // kaydedilmezler (hedef-bağımlı, menüde/toolbar'da yerleri yok) ama lisans kapısı, // kullanım telemetrisi, korelasyon kapsamı ve istisna koruması aynen işler — // jestten çalışan eylem de tek tek lisanslanabilir/ücretlenebilir. const auto inlineKomut = [&](const char* grup, const char* ad, const char* kimlik, std::function fn) { MenuOge o{grup, ad, "", 0, std::move(fn)}; o.kimlik = kimlik; cekirdek.komutCalistir(o, "radyal"); }; // Seçilen YAPRAK öğe → inline eylem VEYA eşlenmiş komut + kapat. const auto ogeCalistir = [&](const girdi::MenuOgeSecim& s) { const std::string k = s.komutKimlik; const u32 hedef = sonPolitikaHedef; Dugum* hd = hedef ? sahne.bul(hedef) : nullptr; if (k == "sec" && hd) inlineKomut("Seçim", "Nesne Seç (jest)", "secim.nesne", [&sahne, hedef](Cekirdek&) { sahne.secimTemizle(); sahne.sec({hedef, 0}, false); }); else if (k == "yakinlas" && hd) inlineKomut("Görünüm", "Nesneye Yakınlaş (jest)", "gorunum.nesneye_yakinlas", [&kamera, hd](Cekirdek&) { kamera.sigdir(hd->dunyaMerkez(), hd->dunyaYaricap() + 0.4f); }); else if (k == "agirlik" && hd && hd->indeksSayi > 0) // yalnız katı/mesh (datum çökme fix) inlineKomut("Görünüm", "Hızlı 3B Menü (jest)", "gorunum.hizli3d", [&hizli3dKimlik, &hizli3dAcik, &hizliDurum, &io, hedef](Cekirdek&) { hizli3dKimlik = hedef; hizli3dAcik = true; hizliDurum.hizli3dAcilisX = io.MousePos.x; hizliDurum.hizli3dAcilisY = io.MousePos.y; }); else if (k == "gizle" && hd) inlineKomut("Görünüm", "Gizle/Göster (jest)", "gorunum.gizle", [&gorunurDegistir, hedef, hd](Cekirdek&) { gorunurDegistir(hedef, !hd->gorunur); }); else if (k == "sil" && hedef) inlineKomut("Düzenle", "Seçileni Sil (jest)", "duzenle.sil", [&sahne, hedef](Cekirdek& c) { c.uygula(std::make_unique(sahne, std::vector{hedef})); }); else if (k == "kisit") // Sketcher paneli (kısıt bölümü) inlineKomut("Sketch", "Kısıt Paneli (jest)", "sketch.kisit_paneli", [&panelSketch](Cekirdek&) { panelSketch = true; }); else if (const MenuOge* o = komutBul(k)) cekirdek.komutCalistir(*o, "radyal"); sonPolitika = girdi::PolitikaKarar{}; // menü kapat }; // Tüm bağlamlar radyal (nested destekli) araç halkası ile çizilir. Ara-öğe // (cocuklar dolu) → alt-halka; yaprak → ogeCalistir. Çocuk AracOge dizileri // frame boyunca yaşamalı (raw pointer) → cocukBuf'ta tutulur. std::array oge{}; std::array, 16> cocukBuf{}; // Etkin olmayan öğeler radyal bağlam menüsünde GİZLENİR (soluk/pasif DEĞİL). // aracHalkasi GÖRÜNÜR sırayla indeks döndürür → orijinal politika indeksine // harita ile çeviririz (yaprak + alt-halka çocuğu ayrı ayrı). std::array ogeHarita{}; std::array, 16> cocukHarita{}; const int kaynak = (int)std::min(sonPolitika.ogeler.size(), oge.size()); int n = 0; for (int i = 0; i < kaynak; ++i) { const auto& s = sonPolitika.ogeler[i]; if (!s.cocuklar.empty()) { // ara-öğe: yalnız ETKİN çocuklarını göster const int cn = (int)std::min(s.cocuklar.size(), cocukBuf[n].size()); int cv = 0; for (int j = 0; j < cn; ++j) { const auto& cs = s.cocuklar[j]; if (!ogeEtkin(cs)) continue; // etkin olmayan çocuk gizle cocukBuf[n][cv].etiket = cs.etiket.c_str(); cocukBuf[n][cv].simge = ui::Simge(cs.simge); cocukBuf[n][cv].etkin = true; cocukHarita[n][cv] = j; ++cv; } if (cv == 0) continue; // hiç etkin çocuk yok → ara-öğeyi tümüyle gizle oge[n].etiket = s.etiket.c_str(); oge[n].simge = ui::Simge(s.simge); oge[n].cocuklar = cocukBuf[n].data(); oge[n].cocukSayi = cv; oge[n].etkin = true; } else { // yaprak if (!ogeEtkin(s)) continue; // etkin değil → gizle oge[n].etiket = s.etiket.c_str(); oge[n].simge = ui::Simge(s.simge); oge[n].etkin = true; } ogeHarita[n] = i; ++n; } const int dizilim = sonPolitika.radyal ? (int)ui::AracDizilim::Radyal : (int)ui::AracDizilim::Yatay; int cocukIdx = -1; const int e = ui::aracHalkasi("baglam", sonPolitikaKonum, true, oge.data(), n, (ui::AracDizilim)dizilim, &cocukIdx); if (e == ui::ARAC_KAPAT) sonPolitika = girdi::PolitikaKarar{}; else if (e >= 0 && e < n) { const auto& sel = sonPolitika.ogeler[ogeHarita[e]]; // görünür→orijinal if (cocukIdx >= 0 && cocukIdx < oge[e].cocukSayi) ogeCalistir(sel.cocuklar[cocukHarita[e][cocukIdx]]); // alt-halka yaprağı (harita) else if (sel.cocuklar.empty()) ogeCalistir(sel); // üst-seviye yaprak } } } // namespace fiko