-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Layout using CCSS principles #268
Comments
I think we should restrict imgui from unnecessary bloat. |
+1 If something like this is made it should be layered outside on top of ImGui (like some contrib lib or something similar) I (personally) would like to avoid it inside core ImGui. |
I haven't looked the link yet so it's hard to tell. Better layout features are desirable but I don't know what form they'll take yet. It certainly wouldn't hurt to study those existing techniques and see what can be borrowed from them. |
Agreed. I just don't want there to be a requirement of some CSS 'script' to make the layout but ideas are of course good to use. |
Yes, that's what I meant - to get inspiration about how to very easily (in very few lines of code) specify rich layout compatible with many different screen/window sizes and ratios and possibly implement (some of) these ideas in ImGui. Btw, the purpose of this post is to make a rock-solid roadmap for layouting in ImGui, so you really can sleep peacefully without waking up with an idea "quickly, I have to fix this bug and implement this request in ImGui". This should make you more relaxed as you described in #259 . |
👍 |
Here is one of such contraints solver in c++ |
Nice list of good existing solutions implementing the Cassowary algorithm or similar can be found on http://overconstrained.io/ . |
The main problem with those techniques is that they are not suited to the immediate layout we're doing at the moment. Right now we basically have no information of the preceding and upcoming widgets when laying out something. A few parts of ImGui are relying on passing data across frames but it's more occasional than generalized and it has its shortcomings. I'm not even sure at which sort of granularity you would like to use that sort of constraints. Perhaps describe one or more specific example pertaining to ImGui use and we can see how to work from that. The immediate use case I can think of are columns which really needs to be improved (if only for their initial width). Their declaration could use some sort of constraint system. |
Yes, this is an issue for fully constraint-based layouting. I don't see though any obstacles for use in smaller parts or containers (e.g. the columns you mentioned).
Relying on passing data across frames would be only an optimization (introducing a new whole bunch of problems dealing with invalidation) as Cassowary should be run for every frame (this should be the very basic idea of immediate mode GUIs).
Regarding some example, I envision something like having a list of constraints for each widget. This list would be passed to overloaded widget functions instead of fixed sizes. These overloaded widget functions might be thin wrappers over the current low-level widget functions. Each widget function wrapper would connect the list of constraints to the global ImGui context object and once the end of container (or the whole frame) is reached, Cassowary would be automatically run and the computed sizes finally passed to the low-level (original) functions and these can do what's necessary. The issue with this approach is, that it defers the execution, which won't probably work well if combined with low-level widget functions (I didn't check internals of ImGui, so I can't reason about this). |
Feel free to try Cassowary in action on http://cacaodev.github.io/Autolayout/ConstraintEditor/ . |
That's the entire point of ImGui to not defer the execution. The API only makes sense because the execution is immediate, and the execution requires to know the position/size of widgets. If the execution isn't immediate all the API have to be changed and you don't have an ImGui anymore. The way Unity old IMGUI and other implementations often solved this for example is to use a multi-pass approach (their OnGUI function is called multiple times). It help solving that sort of problem very easily but it adds severe restriction on the freedom to use the gui system. Suddenly you can't just call ui stuff anywhere in your code, it has to be in a spot that can be passed over multiple times and that affects architecture. The reason for passing data across frames would be so that frame N+1 can use the computed result from frame N, which makes sense for stableish form of layout. It's a sort of workaround defacto multi-pass. This is what I am doing e.g. for menus, on their frame 0 they are calculating size and being hidden, and only being displayed from frame 1. So what I am envisioning is a system that store those data across frames and is designed to be flexible enough that it does the right job in the typical case of having a stable layout but doesn't break badly when the layout changes. That system could also be expressed as user-side helper to allow the user feeding data priorhand. |
@ocornut thank you for the explanation of some internals - the N+1 "hack" is a small surprise for me ;). Anyway, there is another approach:
This is enough independent from widget functions and allows the programmer to decide whether to use the computed position and size or not. The first step is the only place where ImGui can interact with the layouting system and help the programmer. ImGui can e.g. provide a minimal set of default/recommended constraints for each such widget, so that one doesn't have to manually come up with sane constraints e.g. for minimal size of a radio button. Hm, this sounds really interesting to me - I've never assumed, that I could "correct" or somehow adjust or completely reuse (for any purpose) internally computed sizes and positions. That opens a whole new dimension of possibilities. Thanks guys for this discussion! |
There shouldn't be any code duplication (except for the corner case described below). Imagine something like the following pseudocode:
I've deliberately avoided an example with any widget having variable minimum/maximum width/height as part of the constraint. In practice this is only text under certain weird conditions (I can't think of any good example except for an imaginary GUI version of the UNIX It may sound like an issue, but actually it doesn't matter at all, because no widgets are sized according to the text dimensions as the text has very different length every single time (e.g. due to translations and/or just different system font settings and/or different font and/or different DPI and/or whatever) and nobody wants UI changing its geometry based on some changes in text (if you don't happen to be a designer, then just ask any to get a proof, that changing geometry is very unpleasant for the end user). If you insist you need it, you can render the text to some temporary buffer tb to get the size and either throw away tb and re-render the text again to the final buffer or not throw tb away and instead of re-rendering just copy the contents of tb over the final buffer. There might be an overloaded function In the case you described, I'd choose some ratio of available width as the column size. Regarding any other scenario, imagine you wanted to rewrite the GitHub pages layout with all its dynamics and properties :) |
I don't see the value of this specific example seeing it can be done perfectly without constraint and in a less cumbersome way. I would have imagined that the purpose of constraint that to solve more interesting layout cases, here we don't have dependencies between the elements. You can express this with something like Now, I can envision the value of this and I think we will evolve toward a similar structure, with tools to calculate the position/size of widget prior-hand. Those tools can specific helpers or a more generic constraint solver. At this point it becomes a matter of syntax but my intuition is that we can have specialized vertical/horizontal layout objects and do most of this simpler and faster. I'd be interested in more convincing examples. (not suggesting this is bad in any way but I need more example to enrich the design process). (
That would apply to most UI but I don't think it applies to my intended typical use of ImGui which is to make very fast tools and rely on as many assumption as possible to make them easily. They are most often tools that are not-localized, will all strings inline, a known font. The user would often want to try minimizing screen real-estate because when dealing with a game engine you are dealing with large amount of data and options. so that sort of pattern to pack the check-box makes sense. Are you using ImGui yourself? |
Hi @ocornut, let me apologize for the delay (life's hard).
According to screenshots of ImGui in the wild, I'm totally certain, that your "intended typical use of ImGui" does unfortunately not match the typical ImGui use of others (which is rather closer to the task I mentioned in #268 (comment) , i.e. "rewrite the GitHub web pages UI layout with all its dynamics and properties"). Anyway, there is a neat, tiny, and fast single-header library for Cassowary - https://github.com/starwing/amoeba . Feel free to add support for it to get both DPI agnostic and physical screen size/ratio agnostic layouts.
Actually Nuklear fits my use cases better. |
Is that mean there is declarative layout support? If anyone create another QT from imgui to support like CSS flexbox using over Facebook iOS and their so call cross platform layout engine: https://facebook.github.io/yoga/ Hopefully there is one project using technology that really cross platform, for now the best might be QT, but the licensing... |
After reading all the issues regarding layout, I came to conclusion, that nobody assumed a possibility of defining the layout using some of the ideas of Constraint Cascading Style Sheets, which is used in some form e.g. in Cocoa. There are several other open source projects dealing with this principle:
Do you think some support for CCSS could be added to ImGui?
The text was updated successfully, but these errors were encountered: