#include "fiko/ui/serit_cubugu.hpp" #include #include #include #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/cekirdek/kayit.hpp" #include "fiko/cekirdek/workbench.hpp" #include "fiko/ui/animasyon.hpp" #include "fiko/ui/bilesen.hpp" #include "fiko/ui/simge.hpp" #include "fiko/ui/tema.hpp" #include "imgui_internal.h" namespace fiko::ui { namespace { // UTF-8 güvenli: ad'ı maxW'ye sığdır; taşarsa "…". (workbench_secici kalıbı, yerel.) void sigdir(char* out, int outSz, const char* ad, float fontB, float maxW) { ImFont* f = ImGui::GetFont(); ImFontBaked* bk = f->GetFontBaked(fontB); if (!bk) { std::strncpy(out, ad, outSz - 1); out[outSz - 1] = 0; return; } const float olcek = fontB / bk->Size; float W = 0.0f; for (const char* s = ad; *s;) { unsigned c = 0; s += ImTextCharFromUtf8(&c, s, nullptr); if (!c) break; if (const ImFontGlyph* g = bk->FindGlyph((ImWchar)c)) W += g->AdvanceX * olcek; } if (W <= maxW) { std::strncpy(out, ad, outSz - 1); out[outSz - 1] = 0; return; } const ImFontGlyph* eg = bk->FindGlyph((ImWchar)0x2026); const float lim = maxW - (eg ? eg->AdvanceX * olcek : 0.0f); float acc = 0.0f; int oi = 0; for (const char* s = ad; *s;) { const char* prev = s; unsigned c = 0; s += ImTextCharFromUtf8(&c, s, nullptr); if (!c) break; const ImFontGlyph* g = bk->FindGlyph((ImWchar)c); const float aw = g ? g->AdvanceX * olcek : 0.0f; if (acc + aw > lim) break; const int len = (int)(s - prev); if (oi + len >= outSz - 4) break; std::memcpy(out + oi, prev, len); oi += len; acc += aw; } const char ell[] = "\xE2\x80\xA6"; // … if (oi + 3 < outSz - 1) { std::memcpy(out + oi, ell, 3); oi += 3; } out[oi] = 0; } // Yatay ortalanmış metin. void metinOrta(ImDrawList* dl, const char* s, ImVec2 merkez, float fb, ImU32 renk) { if (!s || !s[0]) return; ImFont* f = ImGui::GetFont(); const ImVec2 ts = f->CalcTextSizeA(fb, FLT_MAX, 0.0f, s); dl->AddText(f, fb, {merkez.x - ts.x * 0.5f, merkez.y - ts.y * 0.5f}, renk, s); } } // namespace const char* SeritCubugu::etiketBul(const std::string& grup) const { for (const auto& p : ayar_.grupEtiket) if (p.first == grup) return p.second.c_str(); return nullptr; } bool SeritCubugu::grupGizli(const std::string& grup) const { for (const auto& g : ayar_.gizliGruplar) if (g == grup) return true; return false; } void SeritCubugu::duzenKur(Cekirdek& c, const std::string& aktifWb) { slotlar_.clear(); gruplar_.clear(); const auto& hepsi = c.menuler().hepsi(); const auto zaten = [&](const std::string& grup) { for (const auto& gg : gruplar_) if (*gg.ad == grup) return true; return false; }; const auto grupIsle = [&](const std::string& grup) { if (grup.empty() || grupGizli(grup) || zaten(grup)) return; const int bas = (int)slotlar_.size(); const std::string* adPtr = nullptr; // Grup içi öğeleri yuvalara böl: altGrup'u aynı olanlar TEK flyout kümesi; boş // altGrup → bağımsız yuva. Küme konumu ilk üyenin görülme sırasıyla belirlenir. std::unordered_map kumeYuva; // altGrup → slotlar_ index for (int i = 0; i < (int)hepsi.size(); ++i) { const MenuOge& o = hepsi[i]; if (o.grup != grup) continue; if (!(o.workbench.empty() || o.workbench == aktifWb)) continue; // Etkin olmayan komut GİZLENMEZ → soluk/disabled gösterilir (CATIA davranışı): // kullanıcı komutu bulur, ön-koşulunu (ör. Pad → sketch gerekli) tooltip'ten anlar. if (!adPtr) adPtr = &o.grup; // registry'deki stabil string (kare boyu geçerli) if (o.altGrup.empty()) { slotlar_.push_back({i, {i}, false, {}}); } else { auto it = kumeYuva.find(o.altGrup); if (it == kumeYuva.end()) { const std::string kume = grup + "/" + o.altGrup; kumeYuva.emplace(o.altGrup, (int)slotlar_.size()); slotlar_.push_back({i, {i}, false, kume}); } else { slotlar_[it->second].uyeler.push_back(i); } } } // Küme yuvalarını sonlandır: flyout bayrağı + son-kullanılan temsilci. for (int s = bas; s < (int)slotlar_.size(); ++s) { Yuva& y = slotlar_[s]; if (y.uyeler.size() > 1) { y.flyout = true; auto sk = sonKullanilan_.find(y.kume); if (sk != sonKullanilan_.end()) { for (int u : y.uyeler) if (u == sk->second) { y.temsilci = u; break; } } } } const int son = (int)slotlar_.size(); if (son > bas) gruplar_.push_back({adPtr, etiketBul(grup), bas, son}); }; for (const std::string& g : ayar_.grupSira) grupIsle(g); for (const MenuOge& o : hepsi) grupIsle(o.grup); } bool SeritCubugu::butonCiz(ImDrawList* dl, Cekirdek& c, const MenuOge& o, float bx, float top, float h, int idx, unsigned baglamBiti) { const Tema& t = tema(); const ImVec2 bMin{bx, top}, bMax{bx + ayar_.butonGen, top + h}; ImGui::SetCursorScreenPos(bMin); ImGui::PushID(idx); const bool etkin = !o.etkinMi || o.etkinMi(c); const bool tik = ImGui::InvisibleButton("##sb", {ayar_.butonGen, h}); const ImGuiID bid = ImGui::GetItemID(); const bool ustunde = ImGui::IsItemHovered(); const bool hover = etkin && ustunde; // Bağlam-uygun mu? (imleç-altı kategori bu komutun hedefMaske'sinde). Hafif nabız vurgu. const bool baglamUygun = etkin && baglamBiti && (o.hedefMaske & baglamBiti); const float hf = animf(bid, hover ? 1.0f : 0.0f, 14.0f); const float pr = yay(bid + 7, (etkin && ImGui::IsItemActive()) ? 1.0f : 0.0f); const float d = 1.5f * pr; const ImVec2 rMin{bMin.x + d, bMin.y + d}, rMax{bMax.x - d, bMax.y - d}; if (baglamUygun && !hover) { // bağlam parlaması (hover kendi glow'unu ezer) const float nb = 0.55f + 0.35f * nabiz(0.9f); glowCerceve(dl, rMin, rMax, t.vurgu2, t.yuvarlak, nb); } if (hover) glowCerceve(dl, rMin, rMax, t.vurgu, t.yuvarlak, hf); const float bgVurgu = 0.28f * hf + (baglamUygun ? 0.18f : 0.0f); dl->AddRectFilled(rMin, rMax, u32(karisim(t.cerceve, t.vurgu, bgVurgu), etkin ? 1.0f : 0.32f), t.yuvarlak); dl->AddRect(rMin, rMax, baglamUygun ? u32(t.vurgu2, 0.55f) : u32(t.vurgu, 0.10f + 0.45f * hf), t.yuvarlak, 0, baglamUygun ? 1.4f : 1.0f); // Simge — o.simge boşsa ad'ın ilk UTF-8 harfi (yerel tampon; simgeCiz hemen kullanır). char fb[8] = {0}; const char* glif; if (!o.simge.empty()) { glif = o.simge.c_str(); } else { unsigned cc = 0; const int len = ImTextCharFromUtf8(&cc, o.ad.c_str(), nullptr); if (cc && len > 0 && len < 7) { std::memcpy(fb, o.ad.c_str(), len); glif = fb; } else { glif = "\xE2\x97\xBB"; // ◻ } } const ImU32 sr = u32(etkin ? karisim(t.metinSoluk, t.metin, 0.42f + 0.58f * hf) : t.metinSoluk, etkin ? 1.0f : 0.4f); const float cx = (rMin.x + rMax.x) * 0.5f; const float iconY = ayar_.adlariGoster ? (rMin.y + ayar_.butonSimgeB * 0.62f + 2.0f) : (rMin.y + rMax.y) * 0.5f; simgeCiz(dl, Simge(glif), {cx, iconY}, ayar_.butonSimgeB, sr); // Ad (butonun altında, sığmazsa "…"). if (ayar_.adlariGoster) { char buf[40]; sigdir(buf, sizeof(buf), o.ad.c_str(), ayar_.adFont, ayar_.butonGen - 6.0f); const ImU32 ar = u32(etkin ? karisim(t.metinSoluk, t.metin, 0.30f + 0.50f * hf) : t.metinSoluk, etkin ? 0.95f : 0.4f); metinOrta(dl, buf, {cx, rMax.y - ayar_.adFont * 0.5f - 2.0f}, ayar_.adFont, ar); } if (ustunde) { if (etkin) ImGui::SetTooltip("%s", o.ad.c_str()); else ImGui::SetTooltip("%s — şu an kullanılamıyor", o.ad.c_str()); } ImGui::PopID(); return tik && etkin; // komut çalıştırmayı çağıran (yuvaCiz/flyoutPaletiCiz) üstlenir } // ---- Tek yuva: bağımsız düğme ya da flyout kümesi temsilcisi (▾ + palet) ---- void SeritCubugu::yuvaCiz(ImDrawList* dl, Cekirdek& c, const Yuva& y, float bx, float top, float h, unsigned baglamBiti) { const auto& hepsi = c.menuler().hepsi(); if (!y.flyout) { if (butonCiz(dl, c, hepsi[y.temsilci], bx, top, h, y.temsilci, baglamBiti)) c.komutCalistir(hepsi[y.temsilci], "toolbar"); return; } // Flyout temsilcisi: son-kullanılan üye + sağ-alt köşede ▾ üçgeni (küme ipucu). const bool tik = butonCiz(dl, c, hepsi[y.temsilci], bx, top, h, y.temsilci, baglamBiti); const Tema& t = tema(); const float mx = bx + ayar_.butonGen - 4.0f, my = top + h - 4.0f; const bool acik = acikKume_ == y.kume; const ImU32 ur = u32(acik ? t.vurgu : karisim(t.metinSoluk, t.vurgu, 0.5f), 0.95f); dl->AddTriangleFilled({mx - 6.0f, my - 4.0f}, {mx, my - 4.0f}, {mx - 3.0f, my}, ur); if (acik) { // palet açıkken ankrajı her kare tazele (şerit kayması/boyutlanma → doğru konum) acikAnchorMin_ = {bx, top}; acikAnchorMax_ = {bx + ayar_.butonGen, top + h}; } if (tik) { // temsilci tıklandı → paleti aç/kapat (komut çalıştırma paletten) if (acik) acikKume_.clear(); else { acikKume_ = y.kume; acikUyeler_ = y.uyeler; acikAnchorMin_ = {bx, top}; acikAnchorMax_ = {bx + ayar_.butonGen, top + h}; } } } // ---- Açık flyout paleti: temsilcinin üstünde dikey üye listesi (ribbon'dan sonra çizilir) ---- void SeritCubugu::flyoutPaletiCiz(Cekirdek& c, unsigned baglamBiti) { if (acikKume_.empty() || acikUyeler_.empty()) return; const auto& hepsi = c.menuler().hepsi(); const Tema& t = tema(); const float bw = ayar_.butonGen; const float bh = ayar_.butonSimgeB + ayar_.adFont + 12.0f; // ikon + ad-altı kompakt const float pad = 5.0f; const int n = (int)acikUyeler_.size(); const float paletW = bw + pad * 2; const float paletH = n * bh + (n - 1) * ayar_.kBosluk + pad * 2; const ImGuiViewport* vp = ImGui::GetMainViewport(); float px = acikAnchorMin_.x - pad; float py = acikAnchorMin_.y - paletH - 6.0f; // yukarı doğru aç px = std::clamp(px, vp->WorkPos.x + 2.0f, vp->WorkPos.x + vp->WorkSize.x - paletW - 2.0f); if (py < vp->WorkPos.y + 2.0f) py = acikAnchorMax_.y + 6.0f; // yer yoksa aşağı aç ImGui::SetNextWindowViewport(vp->ID); ImGui::SetNextWindowPos({px, py}); ImGui::SetNextWindowSize({paletW, paletH}); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0, 0}); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4{0, 0, 0, 0}); const ImGuiWindowFlags bayrak = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing; ImGui::Begin("##fiko_serit_flyout", nullptr, bayrak); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); ImDrawList* dl = ImGui::GetWindowDrawList(); const ImVec2 mn = ImGui::GetWindowPos(); const ImVec2 mx = {mn.x + paletW, mn.y + paletH}; dl->AddRectFilled(mn, mx, u32(karisim(t.panel, t.arka, 0.10f), 0.98f), t.yuvarlak); glowCerceve(dl, mn, mx, t.vurgu, t.yuvarlak, 0.6f); dl->AddRect(mn, mx, u32(t.kenar, 0.95f), t.yuvarlak, 0, 1.0f); int secIdx = -1; float cy = mn.y + pad; for (int idx : acikUyeler_) { if (idx >= 0 && idx < (int)hepsi.size() && butonCiz(dl, c, hepsi[idx], mn.x + pad, cy, bh, idx, baglamBiti)) secIdx = idx; cy += bh + ayar_.kBosluk; } const bool paletUstunde = ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); ImGui::End(); ImGui::PopStyleColor(); ImGui::PopStyleVar(2); if (secIdx >= 0) { // üye seçildi → çalıştır + son-kullanılan olarak hatırla + kapat c.komutCalistir(hepsi[secIdx], "toolbar"); sonKullanilan_[acikKume_] = secIdx; acikKume_.clear(); } else { // Palet/temsilci dışına tık veya Esc → kapat (temsilci tıkı toggle'ı yukarıda yönetir). const ImVec2 mp = ImGui::GetMousePos(); const bool ankrajUstunde = mp.x >= acikAnchorMin_.x && mp.x <= acikAnchorMax_.x && mp.y >= acikAnchorMin_.y && mp.y <= acikAnchorMax_.y; if ((ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !paletUstunde && !ankrajUstunde) || ImGui::IsKeyPressed(ImGuiKey_Escape)) acikKume_.clear(); } } void SeritCubugu::ciz(Cekirdek& cekirdek) { if (!gorunur_) return; if (cekirdek.menuler().hepsi().empty()) return; if (cekirdek.workbenchler().hepsi().empty()) return; // çökme guard const std::string& aktifWb = cekirdek.workbenchler().aktif(); duzenKur(cekirdek, aktifWb); if (gruplar_.empty()) return; // çizecek grup yok const Tema& t = tema(); const ImGuiViewport* vp = ImGui::GetMainViewport(); const float pad = 8.0f; const float grupLabelH = ayar_.grupFont + 5.0f; const float solGen = 134.0f; const float sagGen = ayar_.sagCiz ? 88.0f : 0.0f; // Grup içerik genişliği (buton + ayraç boşluğu). float grupW = 0.0f; for (size_t gi = 0; gi < gruplar_.size(); ++gi) { const int n = gruplar_[gi].son - gruplar_[gi].bas; grupW += n * ayar_.butonGen + (n > 0 ? (n - 1) * ayar_.kBosluk : 0.0f); if (gi + 1 < gruplar_.size()) grupW += ayar_.grupBosluk; } const float toplam = pad * 2 + solGen + 12.0f + grupW + (sagGen > 0 ? 12.0f + sagGen : 0.0f); // İçerik ekranı aşıyorsa şerit TAM GENİŞLİK olur + grup alanı yatay kaydırılır // (fare tekerleği). Böylece taşan gruplar (Feature vb.) erişilebilir kalır. const bool tasiyor = toplam > vp->WorkSize.x; const float genislik = (tasiyor || ayar_.tamGenislik) ? vp->WorkSize.x : std::min(toplam, vp->WorkSize.x); const float x = (tasiyor || ayar_.tamGenislik) ? vp->WorkPos.x : vp->WorkPos.x + (vp->WorkSize.x - genislik) * 0.5f; const float y = vp->WorkPos.y + vp->WorkSize.y - ayar_.yukseklik - 8.0f; ImGui::SetNextWindowViewport(vp->ID); ImGui::SetNextWindowPos({x, y}); ImGui::SetNextWindowSize({genislik, ayar_.yukseklik}); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0, 0}); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4{0, 0, 0, 0}); const ImGuiWindowFlags bayrak = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing; ImGui::Begin("##fiko_serit", nullptr, bayrak); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); ImDrawList* dl = ImGui::GetWindowDrawList(); const ImVec2 mn = ImGui::GetWindowPos(); const ImVec2 mx = {mn.x + genislik, mn.y + ayar_.yukseklik}; // Zemin: gradient panel + neon kenar + hafif dış parlama (arac_cubugu kalıbı). const int vtx0 = dl->VtxBuffer.Size; dl->AddRectFilled(mn, mx, u32(karisim(t.panel, t.arka, 0.15f), 0.96f), t.yuvarlak); ImGui::ShadeVertsLinearColorGradientKeepAlpha( dl, vtx0, dl->VtxBuffer.Size, {mn.x, mn.y}, {mn.x, mx.y}, u32(karisim(t.panel, t.vurgu, 0.05f), 0.96f), u32(karisim(t.panel, t.arka, 0.30f), 0.96f)); glowCerceve(dl, mn, mx, t.vurgu, t.yuvarlak, 0.5f); dl->AddRect(mn, mx, u32(t.kenar, 0.9f), t.yuvarlak, 0, 1.0f); const float butonTop = mn.y + pad; const float butonH = ayar_.yukseklik - grupLabelH - pad * 2; // İmleç-altı bağlam kategorisi bit'i (0 = vurgu yok) — app her kare doldurur. const unsigned baglamBiti = ayar_.baglamBiti ? ayar_.baglamBiti(cekirdek) : 0u; // ---- Sol: aktif workbench çipi (veya solCiz) ---- float cx = mn.x + pad; { const ImVec2 cMin{cx, mn.y + 6.0f}, cMax{cx + solGen, mx.y - 6.0f}; if (ayar_.solCiz) { ImGui::SetCursorScreenPos(cMin); ImGui::BeginGroup(); ayar_.solCiz(cekirdek); ImGui::EndGroup(); } else { const float nb = 0.85f + 0.15f * nabiz(0.7f); dl->AddRectFilled(cMin, cMax, u32(karisim(t.panel, t.vurgu, 0.16f), 0.92f), t.yuvarlak); dl->AddRect(cMin, cMax, u32(t.vurgu, 0.55f * nb), t.yuvarlak, 0, 1.3f); const WorkbenchOge* akt = cekirdek.workbenchler().bul(aktifWb); const float midY = (cMin.y + cMax.y) * 0.5f; if (akt && !akt->simge.empty()) simgeCiz(dl, Simge(akt->simge.c_str()), {cMin.x + 16.0f, midY}, 20.0f, u32(karisim(t.metin, t.vurgu, 0.25f))); if (akt) { char buf[48]; sigdir(buf, sizeof(buf), akt->ad.c_str(), 13.0f, solGen - 36.0f); ImFont* f = ImGui::GetFont(); const ImVec2 ts = f->CalcTextSizeA(13.0f, FLT_MAX, 0.0f, buf); dl->AddText(f, 13.0f, {cMin.x + 30.0f, midY - ts.y * 0.5f}, u32(karisim(t.metinSoluk, t.metin, 0.7f)), buf); } } } cx += solGen + 12.0f; // ---- Grup alanı: sol çip ile sağ (FPS) arasındaki kaydırılabilir bölge ---- const float grupAlanSol = cx; const float grupAlanSag = mx.x - pad - (sagGen > 0 ? sagGen + 12.0f : 0.0f); const float grupAlanW = grupAlanSag - grupAlanSol; const float maxKaydir = std::max(0.0f, grupW - grupAlanW); // Fare tekerleği (şerit üzerinde) → yatay kaydır. Dikey tekerlek yatay kaydırmaya map. if (maxKaydir > 0.0f && ImGui::IsWindowHovered()) { const float tk = ImGui::GetIO().MouseWheel + ImGui::GetIO().MouseWheelH; if (tk != 0.0f) kaydirmaX_ -= tk * 52.0f; } kaydirmaX_ = std::clamp(kaydirmaX_, 0.0f, maxKaydir); // Grup çizimi kaydırma ofsetli + grup alanına kırpılır (ImGui::PushClipRect → hem çizim // hem buton hit-test kırpılır: alan dışındaki butonlar ne görünür ne tıklanır). ImGui::PushClipRect({grupAlanSol, mn.y}, {grupAlanSag, mx.y}, true); cx = grupAlanSol - kaydirmaX_; for (size_t gi = 0; gi < gruplar_.size(); ++gi) { const GrupGorunum& g = gruplar_[gi]; const float gBas = cx; for (int k = g.bas; k < g.son; ++k) { yuvaCiz(dl, cekirdek, slotlar_[k], cx, butonTop, butonH, baglamBiti); cx += ayar_.butonGen + ayar_.kBosluk; } if (g.son > g.bas) cx -= ayar_.kBosluk; // son butondan sonraki fazla boşluğu geri al const char* et = g.etiket ? g.etiket : (g.ad ? g.ad->c_str() : ""); metinOrta(dl, et, {(gBas + cx) * 0.5f, mx.y - grupLabelH * 0.5f - 1.0f}, ayar_.grupFont, u32(t.metinSoluk, 0.85f)); if (gi + 1 < gruplar_.size()) { const float sx = cx + ayar_.grupBosluk * 0.5f; dl->AddLine({sx, mn.y + 8.0f}, {sx, mx.y - 8.0f}, u32(t.kenar, 0.7f), 1.0f); cx += ayar_.grupBosluk; } } ImGui::PopClipRect(); // Taşma göstergesi: kenarlarda soluk gradyan + ok (daha fazla içerik var ipucu). if (kaydirmaX_ > 1.0f) { dl->AddRectFilledMultiColor({grupAlanSol, mn.y + 2}, {grupAlanSol + 22, mx.y - 2}, u32(t.panel, 0.85f), u32(t.panel, 0.0f), u32(t.panel, 0.0f), u32(t.panel, 0.85f)); metinOrta(dl, "\xE2\x80\xB9", {grupAlanSol + 8, (mn.y + mx.y) * 0.5f}, 16.0f, u32(t.vurgu, 0.9f)); } if (kaydirmaX_ < maxKaydir - 1.0f) { dl->AddRectFilledMultiColor({grupAlanSag - 22, mn.y + 2}, {grupAlanSag, mx.y - 2}, u32(t.panel, 0.0f), u32(t.panel, 0.85f), u32(t.panel, 0.85f), u32(t.panel, 0.0f)); metinOrta(dl, "\xE2\x80\xBA", {grupAlanSag - 8, (mn.y + mx.y) * 0.5f}, 16.0f, u32(t.vurgu, 0.9f)); } // ---- Sağ: sagCiz (FPS/kalite) ---- if (ayar_.sagCiz) { ImGui::SetCursorScreenPos( {mx.x - sagGen - pad, mn.y + (ayar_.yukseklik - ImGui::GetFrameHeight()) * 0.5f}); ImGui::BeginGroup(); ayar_.sagCiz(cekirdek); ImGui::EndGroup(); } ImGui::End(); ImGui::PopStyleColor(); ImGui::PopStyleVar(2); // Açık flyout paleti ribbon window'dan SONRA çizilir → üstte kalır, tık paletdedir. flyoutPaletiCiz(cekirdek, baglamBiti); } } // namespace fiko::ui