Skip to content

Problem with PushFont and PopFont with menus #7903

Closed
@voidware

Description

Version/Branch of Dear ImGui:

1.90

Back-ends:

all

Compiler, OS:

Windows

Full config/build information:

No response

Details:

I would like to have a Menu in one font and items within it in another.

If you push a font in order to have a BeginMenu in a different font, but then want some MenuItem in the normal (default) font and call PopFont it will assert fail because the font stack is wrong - unless you manually fix the font stack with a hack.

asserts here in AddText

    IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId);  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
Code example with hackaround:
struct PushIconFont
{
    // class to push and pop the icon font
    bool        _pushed = false;

    void        push()
    {
         ImGui::PushFont(iconFont);
         _pushed = true;
    }

    void        pop()
    {
        if (_pushed)
        {
            ImGui::PopFont();
            _pushed = false;
        }
    }

    static void fixme()
    {
        // XXX big hairy steaming great hack !!
        auto w = ImGui::GetCurrentWindow();
        int z = w->DrawList->_TextureIdStack.Size;
        if (!z)
        {
            auto font = ImGui::GetDefaultFont();
            w->DrawList->PushTextureID(font->ContainerAtlas->TexID);
        }
    }

    PushIconFont()  { push(); }
    ~PushIconFont()  { pop(); }
};

if (ImGui::BeginMenuBar())
 {
     // push the icon font.
     PushIconFont pf;

     // make a menu using the icon font
     if (ImGui::BeginMenu(ICON_MD_MORE_HORIZ)) // three dots "..."
     {
         // we now want some menu items in the default font
         pf.pop(); // pop off the icon font

         // this fixes the stack imbalance so we can use the base font
         // XXX THIS IS A STEAMING HACK !!
         pf.fixme();

         // !! BANG the following line will asset fail unless
         // `fixme` is done above.

         // make some normal menu items
         if (ImGui::MenuItem("Something")) doSomething();
         if (ImGui::MenuItem("Something else")) doSomethingElse();

         ImGui::EndMenu();            
     }

     ImGui::EndMenuBar();    
 }

The above code has a Steaming Great Hack in fixme to do this.

I can explain what is happening:

  1. PushFont is called which pushes onto g.FontStack and PushTextureID pushes onto the drawlist TextureIdStack. So we're on both stacks.

  2. BeginMenu is cool until you click on it. It creates a popup which calls Begin. Begin ascertains we're first_begin_of_the_frame and calls window->DrawList->_ResetForNewFrame() which clears the TextureIdStack.

But hey, the g.FontStack is still pushed!

The workaround is to pop as normal (which has the side-effect of popping the TextureIdStack to NULL) then manually pushing it back in fixme. Bluh!

Is this an ImGui bug, perhaps a limitation or have i gone mad (again) ?

Thanks.

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

// Here's some code anyone can copy and paste to reproduce your issue
ImGui::Begin("Example Bug");
MoreCodeToExplainMyIssue();
ImGui::End();

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions