#include "fiko/ui/komut_paleti.hpp" #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/cekirdek/fiko_son_dosyalar.hpp" #include "fiko/sahne/sahne.hpp" #include "fiko/ui/bilesen_ek.hpp" #include "fiko/ui/fiko_universal_arama.hpp" #include "fiko/ui/tema.hpp" #include "imgui.h" namespace fiko::ui { void komutlariTopla(Cekirdek& cekirdek, KomutKaydi& kayit) { kayit.komutlariTemizle(); // komutları temizle, MRU geçmişini koru for (const MenuOge& o : cekirdek.menuler().hepsi()) { // Arama TÜM komutları kapsar (aktif olmayan workbench dahil) — "eksik kalmasın". // Yalnız o an bağlam-geçersiz (etkinMi=false) komutlar atlanır (çalıştırılamaz). if (o.etkinMi && !o.etkinMi(cekirdek)) continue; Komut k; k.ad = o.ad; k.kategori = o.grup; // Merkezi dispatch: doğrudan f(cekirdek) DEĞİL — komutCalistir (lisans gate + KomutCalisti // denetim olayı) üzerinden. MenuOge kopyalanır (ad/grup event payload'u için). k.calistir = [&cekirdek, oge = o] { cekirdek.komutCalistir(oge, "palet"); }; kayit.ekle(std::move(k)); } } void universalKaynaklariKur(FikoUniversalArama& arama, KomutKaydi& paletKayit, Cekirdek& cekirdek, Sahne& sahne, std::function nesneyeOdakla, FikoSonDosyalar& sonDosyalar, std::function dosyaAc) { arama.kaynaklariTemizle(); // (a) KOMUT kaynagi — mevcut komut arama BIREBIR: her aramada komutlariTopla ile // guncel komut listesi (aktif workbench + global) FikoAramaOgesi'ye cevrilir. arama.kaynakEkle(FikoAramaKaynagi{ "Komut", [&cekirdek, &paletKayit]() { komutlariTopla(cekirdek, paletKayit); std::vector ogeler; const auto& komutlar = paletKayit.hepsi(); ogeler.reserve(komutlar.size()); for (const Komut& k : komutlar) { ogeler.push_back(FikoAramaOgesi{ k.ad, "Komut", [&paletKayit, ad = k.ad]() { // MRU tutarli + calistir: registry uzerinden ada gore bul. for (const Komut& kk : paletKayit.hepsi()) if (kk.ad == ad) { paletKayit.calistir(kk); return; } }}); } return ogeler; }}); // (b) NESNE kaynagi — sahnedeki adlandirilmis dugumler; calistir = sec + odakla. // Ekran-sabit referans/salt-cizgi (datum/CAM) atlanir (adsiz/gecici — arama gurultusu). arama.kaynakEkle(FikoAramaKaynagi{ "Nesne", [&sahne, nesneyeOdakla]() { std::vector ogeler; for (const Dugum& d : sahne.dugumler()) { if (d.ad.empty()) continue; if (d.tip == DugumTip::Duzlem || d.tip == DugumTip::Eksen || d.tip == DugumTip::EksenSistemi || d.tip == DugumTip::TakimYolu) continue; ogeler.push_back(FikoAramaOgesi{ d.ad, "Nesne", [&sahne, nesneyeOdakla, kimlik = d.kimlik]() { sahne.secimTemizle(); sahne.sec(SecimOge{kimlik, 0}, false); if (nesneyeOdakla) nesneyeOdakla(kimlik); }}); } return ogeler; }}); // (c) DOSYA kaynagi — son kullanilan dosyalar (MRU); calistir = uzantiya gore ac. // Ad = dosya adi (kisa), etiket icin salt-okuma; tam yol calistir'a gecer. arama.kaynakEkle(FikoAramaKaynagi{ "Dosya", [&sonDosyalar, dosyaAc]() { std::vector ogeler; for (const std::string& yol : sonDosyalar.hepsi()) { std::string ad = yol; if (const size_t s = ad.find_last_of("/\\"); s != std::string::npos) ad = ad.substr(s + 1); ogeler.push_back(FikoAramaOgesi{ ad, "Dosya", [dosyaAc, yol]() { if (dosyaAc) dosyaAc(yol); }}); } return ogeler; }}); // (d) WORKBENCH kaynagi — CATIA calisma ortamlari; calistir = o workbench'e gec. arama.kaynakEkle(FikoAramaKaynagi{ "Workbench", [&cekirdek]() { std::vector ogeler; for (const WorkbenchOge& w : cekirdek.workbenchler().hepsi()) ogeler.push_back(FikoAramaOgesi{ w.ad, "Workbench", [&cekirdek, kimlik = w.kimlik]() { cekirdek.workbenchler().aktifAyarla(cekirdek, kimlik); }}); return ogeler; }}); } void komutPaletiCiz(KomutPaleti& palet) { if (!palet.acikMi()) return; const Tema& t = tema(); ImGuiIO& io = ImGui::GetIO(); const ImVec2 ekran = io.DisplaySize; // Karartilmis tam-ekran zemin (odak paletide). ImGui::GetBackgroundDrawList()->AddRectFilled(ImVec2(0, 0), ekran, IM_COL32(4, 6, 12, 175)); const float gen = std::min(660.0f, ekran.x * 0.62f); ImGui::SetNextWindowPos(ImVec2(ekran.x * 0.5f, ekran.y * 0.24f), ImGuiCond_Always, ImVec2(0.5f, 0.0f)); ImGui::SetNextWindowSize(ImVec2(gen, 0.0f), ImGuiCond_Always); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(14, 14)); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 12.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.5f); ImGui::PushStyleColor(ImGuiCol_WindowBg, t.panel); ImGui::PushStyleColor(ImGuiCol_Border, t.vurgu); const ImGuiWindowFlags bayrak = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; if (ImGui::Begin("##komut_paleti", nullptr, bayrak)) { // Klavye gezinme. if (ImGui::IsKeyPressed(ImGuiKey_Escape)) palet.kapat(); if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) palet.asagi(); if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) palet.yukari(); const bool navOldu = ImGui::IsKeyPressed(ImGuiKey_DownArrow) || ImGui::IsKeyPressed(ImGuiKey_UpArrow); const bool enter = ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter); // Arama kutusu — palet.sorgu() kanonik; her kare tampona kopyalanir. char tampon[256]; std::snprintf(tampon, sizeof(tampon), "%s", palet.sorgu().c_str()); if (ImGui::IsWindowAppearing()) ImGui::SetKeyboardFocusHere(); const char* ipucu = palet.universalMi() ? "Komut veya nesne ara…" : "Komut ara…"; if (aramaKutusu("##palet_ara", tampon, sizeof(tampon), ipucu, gen - 28.0f)) { palet.sorguAyarla(tampon); } ImGui::Dummy(ImVec2(0, 6)); // Sonuclar iki moddan gelir: universal (komut+nesne+...) veya klasik komut. // Her satiri (ad + sagda soluk kategori rozeti) tek ciz — mod-agnostik lambda. const int adet = palet.sonucSayisi(); if (adet == 0) { ImGui::PushStyleColor(ImGuiCol_Text, t.metinSoluk); ImGui::TextUnformatted(" Eslesme yok"); ImGui::PopStyleColor(); } else { const float satir = ImGui::GetTextLineHeightWithSpacing() + 4.0f; const int gorMax = 9; // gorunur satir sayisi (fazlasi kaydirilir) const float yuksek = satir * std::min(adet, gorMax); const ImVec4 vurguSoluk(t.vurgu.x, t.vurgu.y, t.vurgu.z, 0.14f); const ImVec4 vurguSecili(t.vurgu.x, t.vurgu.y, t.vurgu.z, 0.24f); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_HeaderHovered, vurguSoluk); ImGui::PushStyleColor(ImGuiCol_Header, vurguSecili); if (ImGui::BeginChild("##palet_liste", ImVec2(0, yuksek), false, ImGuiWindowFlags_NoScrollbar)) { const int secili = palet.seciliIndeks(); const bool uni = palet.universalMi(); const auto& kSonuc = palet.sonuclar(); // klasik mod const auto& uSonuc = palet.universalSonuclar(); // universal mod for (int i = 0; i < adet && i < 60; ++i) { const bool aktif = (i == secili); ImGui::PushID(i); // Mod-bagimsiz ad + kategori + (varsa) kisayol. std::string ad, kategori, kisayol; if (uni) { ad = uSonuc[i].ad; kategori = uSonuc[i].kategori; } else { const Komut* k = kSonuc[i]; ad = k->ad; kategori = k->kategori; kisayol = k->kisayol; } // Sol: ad + (klasik komut kategorisi/kisayol satir-ici, eski gorunum korunur). // Klasik modda kategori/kisayol ad'dan SONRA normal renkte eklenir. std::string ekEtiket; if (!uni && !kategori.empty()) ekEtiket += " · " + kategori; if (!kisayol.empty()) ekEtiket += " [" + kisayol + "]"; // Selectable BOS etiketle: tik/secim/layout korunur, kendi metnini CIZMEZ // (metni asagida drawlist ile karakter-karakter, eslesmeler vurgulu ciziyoruz). const float satirYuk = ImGui::GetTextLineHeight(); char gizliId[16]; std::snprintf(gizliId, sizeof(gizliId), "##satir_%d", i); if (ImGui::Selectable(gizliId, aktif, 0, ImVec2(0, satirYuk))) { palet.seciliAyarla(i); palet.onayla(); } // Metni manuel ciz: ad karakter-karakter (eslesenler ACCENT/vurgu rengi), // ardindan ek etiket (klasik kategori/kisayol) normal metin renginde. ImDrawList* dl = ImGui::GetWindowDrawList(); const ImVec2 satirMin = ImGui::GetItemRectMin(); const float metinY = satirMin.y; // Selectable yuksekligi = metin satiri, hizali const ImU32 renkNormal = ImGui::GetColorU32(t.metin); const ImU32 renkVurgu = ImGui::GetColorU32(t.vurgu); const std::vector eslesenler = bulanikEslesmePozisyonlari(palet.sorgu(), ad); size_t epIdx = 0; float cx = satirMin.x; for (int c = 0; c < (int)ad.size(); ++c) { const bool vurgulu = epIdx < eslesenler.size() && eslesenler[epIdx] == c; if (vurgulu) ++epIdx; const char karakter[2] = {ad[c], '\0'}; dl->AddText(ImVec2(cx, metinY), vurgulu ? renkVurgu : renkNormal, karakter); cx += ImGui::CalcTextSize(karakter).x; } if (!ekEtiket.empty()) { dl->AddText(ImVec2(cx, metinY), renkNormal, ekEtiket.c_str()); } // Universal modda: sagda soluk kategori rozeti (Komut/Nesne ayirt edilir). if (uni && !kategori.empty()) { const float saginX = ImGui::GetItemRectMax().x; const ImVec2 boyut = ImGui::CalcTextSize(kategori.c_str()); dl->AddText(ImVec2(saginX - boyut.x - 4.0f, metinY), ImGui::GetColorU32(t.metinSoluk), kategori.c_str()); } if (aktif && navOldu) ImGui::SetScrollHereY(0.5f); ImGui::PopID(); } } ImGui::EndChild(); ImGui::PopStyleColor(3); } if (enter) palet.onayla(); } ImGui::End(); ImGui::PopStyleColor(2); ImGui::PopStyleVar(3); } } // namespace fiko::ui