Immediate-Mode-UI / Nuklear

A single-header ANSI C immediate mode cross-platform GUI library
https://immediate-mode-ui.github.io/Nuklear/doc/index.html
Other
9.24k stars 560 forks source link

How to get TAB to navigate between edit widgets? #59

Open ronaaron opened 4 years ago

ronaaron commented 4 years ago

I've got a layout with labels on the left and edit controls on the right. Everything works nicely, but I want to be able to hit TAB (for instance) to move from one 'field' to the next.

What is the proper way to accomplish this?

ronaaron commented 4 years ago

OK, so just to say I do have a way to do it, but it seems like much more work than makes sense.

Check for KEY_TAB pressed in the render loop, and increment a counter; if the edit being created matches the counter, set the edit focus. Some other mechanism would be much more friendly.

dumblob commented 4 years ago

Thanks for asking and glad you already found the "recommended" solution.

Some other mechanism would be much more friendly.

I'm not sure we would want something like that. There would need to be a transparent way how to determine which widget has widget in the current frame and which widget will get it after receiving Shift+Tab (backward) or just Tab (forward). Such thing is not easy and we would probably end up with just saying "the last rendered" widget for Shift+Tab and "the next to be rendered widget" for Tab. But that's still far from being transparent/unambiguous - imagine all the if-else logic for widget creation. Furthermore there are popups and stuff (messing with the logical "previous widget" and "next widget" transparency). This would get messy very early.

So I think the solution with an explicit variable (e.g. counter) is the best to my knowledge :wink:. Thoughts?

ronaaron commented 4 years ago

The real difficulty is that because of immediate-mode, you don't really have knowledge of all the widgets which might exist during a frame, as you would with traditional GUIs.

That said, if there were a 'tabbing order' field, say, in each widget, where the programmer assigned that order (or it could alternatively be auto-assigned in widget-creation order), then it would be possible to handle Tab/Shift+Tab inside Nuklear and just give the focus to the next widget in the assigned order.

Possible?

dumblob commented 4 years ago

That said, if there were a 'tabbing order' field, say, in each widget, where the programmer assigned that order (or it could alternatively be auto-assigned in widget-creation order), then it would be possible to handle Tab/Shift+Tab inside Nuklear and just give the focus to the next widget in the assigned order.

That's what I described above as a problematic approach. But how would you handle (in a more readable and easier way than your current solution) all the cases where the programmer wouldn't want neither the default ordering and maybe not even the at-compile-time-known ordering (because that changes in accordance to which widgets will get drawn and which not in that particular frame based on user input or other criteria)?

Just a smallest example. Nuklear draws stuff mostly (not always due to layouting, compound widgets, popups, etc.) top-down left-right, but that's not how a human perceives the wished "tab order". This "jumpy" experience would get even worse e.g. for arabic people who read buttom-top right-left.

I think this lurks on the edge of this small library - either we would need to introduce full locale support (which is itself bigger than the current nuklear.h) and act accordingly or we'll provide the programmer with some tiny helper - like a generic void pointer "in each widget" (there is no such thing, but maybe struct nk_context could be somehow abused for this purpose) where the programmer can store her struct containing whatever she finds fit - among other things also some ordering information.

ronaaron commented 4 years ago

Actually, I think allowing a 'userdata' pointer for all widgets would be a great thing.

As far as tab ordering, I am assuming that only widgets with a tab-order would get tabbed-to. So part of the widget's construction (or a helper like 'widget_tab_order' or something) would set how to handle tabs for that item.

I guess it works out to be more complex for Nuklear, and could be handled (by me, anyway) if a userdata pointer were available.

dumblob commented 4 years ago

Ok, that doesn't sound bad to me - PRs welcome :wink:.

ronaaron commented 4 years ago

Hey man, I've got two PRs in the queue already...

dumblob commented 4 years ago

Hey man, I've got two PRs in the queue already...

Which is perfect - I'm glad there is the code. We're just out of manpower to review that everything. The thing is immediate mode UIs are really complicated architecturally and all the subtleties are not easy to review :cry:. That's why I'm so persistent about thorough reviews - an ideal case would be to require at least 2 different persons to review each PR in our case, but if there is bunch of people having a different idea (and consensus among them) how to evolve Nuklear, I'm all for it :wink:.

ronaaron commented 4 years ago

I feel your pain :)

I've got several beta-testers giving me valuable feedback as I port 8th from JUCE to Nuklear. It's a ton of work rewriting all the docs, and filling in the missing bits.