Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal Dialogs #249

Closed
Pagghiu opened this issue Jun 23, 2015 · 24 comments
Closed

Modal Dialogs #249

Pagghiu opened this issue Jun 23, 2015 · 24 comments
Labels

Comments

@Pagghiu
Copy link
Contributor

Pagghiu commented Jun 23, 2015

It would be nice to add an begin/end api pair to allow for Modal Dialogs that block inputs to anything else, waiting for and answer.
A gif is worth a thousand words ;)

imguimodaldialog

I think this can be implemented with minor modifications to current functionality in many ways, but I'm not sure what's the best one (tooltips? Begin/EndPopup? Fullscreen window?).
This test gif has been done creating a fullscreen window (to mask the background AND block inputs to windows below) and a child window that contains the text+yes/no controls.
I've also done some hacks to calculate child windows minimum Y size.
Maybe I should use a second window with autosize for the actual dialog content instead of a child win.

Thoughts?

@extrawurst
Copy link
Contributor

OT: this looks great !!!!

@emoon
Copy link
Contributor

emoon commented Jun 23, 2015

+1 for Modal Dialogs

@extrawurst
Copy link
Contributor

+1 Yeah Modal Dialogs are a great addition!

@ocornut
Copy link
Owner

ocornut commented Jun 23, 2015

Seems reasonably easy to implement.

  • Add modal dialogs e.g. BeginModal() they would basically be popups with an additional flag to remove the ability to click elsewhere.
  • The darkening could be a style property, ImGuiCol_ModalDarkening default to ImColor(0, 0, 0, 0.3f) and handled by the library.
  • Then we need a way to automatically center the window, there's currently no way to do it automatically on the first frame the window appears but it should be a simple thing to add as well.

(Nice colors, could you post your styke & font settings somewhere?)

@Pagghiu
Copy link
Contributor Author

Pagghiu commented Jun 23, 2015

Thanks @everyone for joining the discussion!

  1. The way I've been drafting the api is very close to the popup.
    I really think that the closing EndDialog should give a few common presets (YesNo, OkCancel etc.) or a NoButtons if the user really wants to draw/handle the buttons him/herself.
    In the last case he will signal the closing of dialog by setting selection var to 1 or some other known value.
 if(ImGui::CollapsingHeaderIcon("Images", ImGui_fa_camera))
    {
        if (ImGui::ButtonIcon("Live Image", ImGui_fa_camera))
            ImGui::OpenDialog("test dialog");

        if (ImGui::BeginDialog("test dialog", ImVec2((float)view->getWidth(), (float)view->getHeight())))
        {
            ImGui::TextWrapped("Are you sure you want to do this and this and that?");
            ImGui::TextWrapped("Are you sure you want to do this and this and that?");
            ImGui::TextWrapped("Are you sure you want to do this and this and that?");
            static int currentItem = 0;
            ImGui::Combo("Your choice", &currentItem, "Item 1\0Item 2\0Item 3\0Item 4\0\0");
            if (currentItem == 1)
            {
                ImGui::TextWrapped("Good choice!!");
                ImGui::TextWrapped("Good choice!!");
                ImGui::TextWrapped("Good choice!!");
            }

            int selection;
            if (ImGui::EndDialog(ImGui::Dialog_YesNo, &selection))
            {
                if (selection == 0)
                {
                    // Dialog Dismissed with YES (first item)
                }
                else
                {
                    // Dialog Dismissed with NO (second item)
                }
            }           
        }
    // other stuff
    }
  1. ImGuiCol_ModalDarkening 👍 animating the alpha value makes it very nice looking!

  2. The centring was my issue as well...I've done it so that during first frame I render with alpha ~ 0, just to calculate the dialog size, and from the next frame than I use it to center the child window.
    I re-compute the Y size so in case something gets added (like shown in the gif) it will be adjusted in next frame (it's almost not noticeable at 60 fps...)
    Some consideration goes for the centring of the buttons.

Regarding my settings:
Font is DroidSans from extra_fonts.
I'm using ttf icon fonts from http://fortawesome.github.io/Font-Awesome/icons/ and a couple of custom Button/CollapsingHeader functions that render the icon to left/right of text like described in #232

    style.Colors[ImGuiCol_Text] = ImVec4(0.31f, 0.25f, 0.24f, 1.00f);
    style.Colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
    style.Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.68f, 0.68f, 0.68f, 0.00f);
    style.Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 0.19f);
    style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    style.Colors[ImGuiCol_FrameBg] = ImVec4(0.62f, 0.70f, 0.72f, 0.56f);
    style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.95f, 0.33f, 0.14f, 0.47f);
    style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.97f, 0.31f, 0.13f, 0.81f);
    style.Colors[ImGuiCol_TitleBg] = ImVec4(0.42f, 0.75f, 1.00f, 0.53f);
    style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.65f, 0.80f, 0.20f);
    style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.62f, 0.80f, 0.15f);
    style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.39f, 0.64f, 0.80f, 0.30f);
    style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.28f, 0.67f, 0.80f, 0.59f);
    style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.25f, 0.48f, 0.53f, 0.67f);
    style.Colors[ImGuiCol_ComboBg] = ImVec4(0.89f, 0.98f, 1.00f, 0.99f);
    style.Colors[ImGuiCol_CheckMark] = ImVec4(0.38f, 0.37f, 0.37f, 0.91f);
    style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.31f, 0.47f, 0.99f, 1.00f);
    style.Colors[ImGuiCol_Button] = ImVec4(1.00f, 0.79f, 0.18f, 0.78f);
    style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.42f, 0.82f, 1.00f, 0.81f);
    style.Colors[ImGuiCol_ButtonActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.86f);
    style.Colors[ImGuiCol_Header] = ImVec4(0.73f, 0.80f, 0.86f, 0.45f);
    style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.75f, 0.88f, 0.94f, 0.80f);
    style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.46f, 0.84f, 0.90f, 1.00f);
    style.Colors[ImGuiCol_CloseButton] = ImVec4(0.41f, 0.75f, 0.98f, 0.50f);
    style.Colors[ImGuiCol_CloseButtonHovered] = ImVec4(1.00f, 0.47f, 0.41f, 0.60f);
    style.Colors[ImGuiCol_CloseButtonActive] = ImVec4(1.00f, 0.16f, 0.00f, 1.00f);
    style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(1.00f, 0.99f, 0.54f, 0.43f);
    style.Colors[ImGuiCol_TooltipBg] = ImVec4(0.82f, 0.92f, 1.00f, 0.90f);
    style.Alpha = 1.0f;
    style.WindowFillAlphaDefault = 1.0f;
    style.FrameRounding = 4;

@ocornut
Copy link
Owner

ocornut commented Jun 23, 2015

Thanks for the detail. I am working of it (the basic behaviour work but there's no darkening now so it can be confusing).

I called the main function BeginPopupModal() and not just BeginModal() to clarify that it is using the popup system and related popup functions are available.

            if (ImGui::Button("Modal"))
                ImGui::OpenPopup("Modal window");

            bool open = true;
            if (ImGui::BeginPopupModal("Modal window", &open))
            {
                ImGui::Text("Hello dsjfhds fhjs hfj dshfj hds");
                if (ImGui::Button("Close"))
                    ImGui::CloseCurrentPopup();
                ImGui::EndPopup();
            }
  • It would be possible to pass a flag to EndPopup() to close it as you suggested but I don't think it is necessary with the availability of CloseCurrentPopup().
  • I could make buttons close modal dialog by default but I think it would be introduce a rather big inconsistency so I'd rather not.
  • I am not sure the YesNo, OkCancel part is really helpful here, considering it is so easy to create buttons (centered ones less so). Apart from the demo windows ImGui also doesn't assume any English in string literal so that would be a first. And you yourself wouldn't be able to use it considering you have custom buttons. What we should do is to work on better layout helpers and/or add helpers for the specific case of creating a few buttons. It's quite open-ended at this stage and not specifically related to dialogs.
  • basic modal behavior
  • darkening
  • initial position and centering of window (not like normal popups)
  • stacked modal windows
  • demo

@ocornut
Copy link
Owner

ocornut commented Jun 23, 2015

Added darkening, added demo
modal dialog

@ocornut
Copy link
Owner

ocornut commented Jun 23, 2015

Not sure what to do with the centering here. I made the modal windows center on screen at the time they first appear.

  • I tried to make them always recenter but it's particularly odd if you click somewhere and your mouse cursor is not over the same widgets as a result of the window moving.
  • You can still use SetNextWindowPos() to enforce a position.
  • One question left is should I recenter them on subsequent apparition or keep the last position? (if you allowed the window to be moved).
  • I should add the end-user calls perhaps via SetNextWindowPos() to center any window, either an alternative call, or using a magic value (unfortunately negative values are useful..) or an extra parameter.

@adam4813
Copy link

Is there a GetLastWindowWidth like method that could be used in a call to a
method like SetLastWindowPosition?
On Jun 23, 2015 3:33 PM, "omar" [email protected] wrote:

Not sure what to do with the centering here. I made the modal windows
center on screen at the time they first appear.

I tried to make them always recenter but it's particularly odd if you
click somewhere and your mouse cursor is not over the same widgets as a
result of the window moving.

One question left is should I recenter them on subsequent apparition
or keep the last position? (if you allowed the window to be moved).

I should add the end-user calls perhaps via SetNextWindowPos() to
center any window.


Reply to this email directly or view it on GitHub
#249 (comment).

ocornut added a commit that referenced this issue Jun 23, 2015
@ocornut
Copy link
Owner

ocornut commented Jun 23, 2015

@adam4813 What are you trying to do exactly ?

You can use:
GetWindowWidth(); // current window
SetNextWindowPos/Size(); // set pos/size of upcoming window

ocornut added a commit that referenced this issue Jun 23, 2015
@adam4813
Copy link

I was throwing out a suggestion for centering.
On Jun 23, 2015 4:37 PM, "omar" [email protected] wrote:

@adam4813 https://github.com/adam4813 What are you trying to do exactly
?

You can use:
GetWindowWidth(); // current window
SetNextWindowPos/Size(); // set pos/size of upcoming window


Reply to this email directly or view it on GitHub
#249 (comment).

@ocornut
Copy link
Owner

ocornut commented Jun 24, 2015

You are right that it is missing some api to do it without juggling awkwardly with 'next window pos' and 'current window size'.
I will add optional name to the GetWindowPos/Size functions that would cover some more cases.

@Pagghiu
Copy link
Contributor Author

Pagghiu commented Jun 24, 2015

I like your api a lot more than my proposal, I will test it soon and reporting any inconsistency I may eventually found.
@ocornut your speed in implementing this one has been awesome 👍

@emoon
Copy link
Contributor

emoon commented Jun 24, 2015

+1 I will try out this very soonish :)

@Pagghiu
Copy link
Contributor Author

Pagghiu commented Jun 24, 2015

Not sure if it's a bug or wrong usage, posting here anyway.

The following code will cause a wrong Y centering.

        if (ImGui::BeginPopupModal("Load Image?", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
        {
            static int currentItem = 0;
            ImGui::Combo("Your choice", &currentItem, "Item 1\0Item 2\0Item 3\0Item 4\0\0");
            if (currentItem == 1)
            {
                ImGui::TextWrapped("Good choice!!");
            }
            ImGui::Text("This line is a regular text line and works fine");
            ImGui::TextWrapped("This is a wrapped line and will cause a wrong Y centering");

            if (ImGui::ButtonIcon("OK", ImGui_fa_check, ImVec2(120, 40))) { ImGui::CloseCurrentPopup(); }
            ImGui::SameLine();
            if (ImGui::ButtonIcon("Cancel", ImGui_fa_close, ImVec2(120, 40))) { ImGui::CloseCurrentPopup(); }
            ImGui::EndPopup();
        }

Commenting the ImGui::TextWrapped solves the problem.

modalcenteringbug
modalcenteringok

@ocornut
Copy link
Owner

ocornut commented Jun 24, 2015

Yes it's an issue with TextWrapped it doesn't really work with always auto-resizing windows at the moment.

On frame 0 which isnt displayed, while the initial size is being calculated the window is still zero width so wrapped text takes lots of vertical place. Because the modal is centered only once it stays there. There's way around the issue with TextWrapped but not that I'm satisfied with yet. I can probably at least mitigate the problem.

Note that if you call SetNextWindowSize(400,0) prior to opening the dialog to enforce a width it should remove the issue.

@Pagghiu
Copy link
Contributor Author

Pagghiu commented Jun 24, 2015

Ok, I understand, not a big deal actually, it's just important to know, I can skip the wrapped text calls for the first frame if needed.

@ocornut
Copy link
Owner

ocornut commented Jun 24, 2015

If you push an explicit width to wrap, e.g. PushTextWrapPos(400); Text(...)
it'll also work.

@ocornut
Copy link
Owner

ocornut commented Jun 25, 2015

If anybody else tries the dialog let me know. I would like to package 1.41 shortly if possible.

I'm not sure yet what to do with TextWrapped() (it's a known problem for always-auto-resizing window) but I'll handle that separately.

ocornut added a commit that referenced this issue Jun 25, 2015
ocornut added a commit that referenced this issue Jun 25, 2015
…minimum size applied - hopefully no-side effects (#249)
@ocornut
Copy link
Owner

ocornut commented Jun 25, 2015

@adam4813 I just remembered why functions like GetWindowPos/GetWindowSize etc. didn't allow to pass in a name. The reason is that I didn't know how to handle errors properly if the given name didn't match an existing window.
It's ok to assert on incorrect code but I don't really want to assert on incorrect data (or very rarely), especially here it's easy to imagine cases where a window doesn't already exist. I could return a default value for position/size (e.g. zero) but I don't fancy silent errors either. So I left that unsolved and didn't add this parameter to the functions even though as you pointed you it would be useful e.g. to manual center a window, without juggling with next/current window functions.

If I get to implement the ID collision mechanism I envision in the future perhaps imgui will have a non intrusive way to signal errors to the programmer and then it might be a good place to log in a warning in those cases.

@adam4813
Copy link

It isn't a silent error if it is well documented that passing in a window
name that doesn't exist will result in a size of 0 or -1 or similar default
value.
On Jun 24, 2015 9:59 PM, "omar" [email protected] wrote:

@adam4813 https://github.com/adam4813 I just remembered why functions
like GetWindowPos/GetWindowSize etc. didn't allow to pass in a name. The
reason is that I didn't know how to handle errors properly if the given
name didn't match an existing window.
It's ok to assert on incorrect code but I don't really want to assert on
incorrect data (or very rarely), especially here it's easy to imagine cases
where a window doesn't already exist. I could return a default value for
position/size (e.g. zero) but I don't fancy silent errors either. So I left
that unsolved and didn't add this parameter to the functions even though as
you pointed you it would be useful e.g. to manual center a window, without
juggling with next/current window functions.

If I get to implement the ID collision mechanism I envision in the future
perhaps imgui will have a non intrusive way to signal errors to the
programmer and then it might be a good place to log in a warning in those
cases.


Reply to this email directly or view it on GitHub
#249 (comment).

@ocornut
Copy link
Owner

ocornut commented Jun 25, 2015

That would be acceptable I suppose.
However just noticed that for pattern I was trying to cater for (GetWindowSize(name) followed by SetNextWindowPos) the named-get would necessarily fail on the first time the function is called (assuming the Begin is after SetNextWindowPos which makes sense). I think the named get are probably useful but I would like to identify a pattern where they are before just adding them, because right now we've got a functional SetPosCenter already.
A possibility left to do it without SetPosCenter (just because it is healthy to see if we can do it ourselves) is Begin, GetWindowSize (current), SetWindowPos() and that already works but it has a frame of lag hmm. Tricky. I'll put that aside and open a topic later if necessary. I know there's something fishy here but I don't have an immediate blocker to solve.

@ocornut
Copy link
Owner

ocornut commented Jun 27, 2015

Closing this. Note about TextWrapped and name-based Get Pos/Size helpers added in todo list.

@rayzchen
Copy link

rayzchen commented Jun 8, 2024

Note that if you call SetNextWindowSize(400,0) prior to opening the dialog to enforce a width it should remove the issue.

When the window size is not wide enough, this causes a flickering where the dialog appears too tall for one frame and then correct the next frame. However, I find that setting the window size to wider than what it should be just results in no text wrapping. How can I fix this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants