Get unique IDs by reading the Instruction Pointer Register

Started by
27 comments, last by Tispe 11 years, 1 month ago

Maybe I find myself making lots of buttons with similar behavior/logic/etc... So I make a helper function to eliminate the boiler-plate parts of the API.

Is that even a reasonable idea in an IMGUI context? How will you deal with the logic introduced by the immediate result values?

My impression is that if you try to do this, you will end up having to build an entire retained-mode wrapper around your IMGUI, and you'd be better off using an RMGUI in the first place.

I think so. Maybe I have a game-specific debug menu, with some XML (or, more likely, static table in code) configuration:


static DebugButtonData [] =
{
  { "GodMode", toggleGodMode },
  { "NoClip", toggleNoClip },
  { etc... }
} buttons;

for (int i = 0; i < numDebugButtons; ++i)
{
  if (DoButton(buttons[i].label))
  {
    buttons[i].callback();
  }
}

I just don't see why you wouldn't want to be able to write code like that... (Which still leads me back to the previous suggestion - pass in a string and use that (or hash it)).

Advertisement

I think so. Maybe I have a game-specific debug menu, with some XML (or, more likely, static table in code) configuration:


static DebugButtonData [] =
{
  { "GodMode", toggleGodMode },
  { "NoClip", toggleNoClip },
  { etc... }
} buttons;

for (int i = 0; i < numDebugButtons; ++i)
{
  if (DoButton(buttons[i].label))
  {
    buttons[i].callback();
  }
}


Now you want to introduce externally defined callback functions? This just seems like a use-case where IMGUI doesn't fit very well.

What exactly is your fancy IMGUI buying you over a RMGUI at this point? Especially if you are requiring your programmer to manually create unique (and stable) id strings for every single widget?

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I think so. Maybe I have a game-specific debug menu, with some XML (or, more likely, static table in code) configuration:


static DebugButtonData [] =
{
  { "GodMode", toggleGodMode },
  { "NoClip", toggleNoClip },
  { etc... }
} buttons;

for (int i = 0; i < numDebugButtons; ++i)
{
  if (DoButton(buttons[i].label))
  {
    buttons[i].callback();
  }
}

Now you want to introduce externally defined callback functions? This just seems like a use-case where IMGUI doesn't fit very well.

What exactly is your fancy IMGUI buying you over a RMGUI at this point? Especially if you are requiring your programmer to manually create unique (and stable) id strings for every single widget?

No, I just want to be able to use the IMGUI API without restrictions that are based on implementation details. I'm not talking about adding callbacks to the IMGUI API, but being able to write helper code in the client application to reduce boiler-plate kruft. Assuming a simple interface with DoButton, I could write the following code:


if (DoButton("GodMode"))
{
  toggleGodMode();
}
if (DoButton("NoClip"))
{
  toggleNoClip();
}
...

... or I could get sick of copy-pasting and write the code I posted above. Except that __LINE__ tricks break with the shorter/easier version. And given that I need to supply a label for the button anyway ... why not use it (or a hash of it) as the ID?

And given that I need to supply a label for the button anyway ... why not use it (or a hash of it) as the ID?

So there is no possibility of having two different "save" buttons in your GUI?

Labels aren't guaranteed to be unique - you need a fairly strong uniqueness guarantee to keep the GUI intact.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

EWClay's link points out that instead of hashing your file+line string, you just just cast it to a pointer-sized integer.

Regarding macro-generated IDs inhibiting library code / code-reuse, what's stopping you from simply not using the ID-generation macro, and instead passing your own custom IDs for those cases?
If you use a void* for the ID, then the file+line string method works, and you also have the option of using the address of any other object (e.g. An XML node) as a unique ID as well.
In my code I have so far avoided the issue by not passing in an ID at all, and counting widgets internally per frame.

I use the ID to keep track of the current 'hot' and 'active' widgets. Not having fixed IDs means I cannot change the GUI while any widget is hot or active.

So I have a simple rule: the GUI can only change in response to a widget being triggered. At that point the hot and active flags are cleared, and the IDs are free to change.

This is in a level editor. It wouldn't work so well in a game environment where the interface could change in response to game events. There is the option though of explicitly setting the current ID through a function. It also wouldn't work if you used IDs to store information per widget, but I don't do that.

. Maybe I find myself making lots of buttons with similar behavior/logic/etc... So I make a helper function to eliminate the boiler-plate parts of the API. Oops, nothing works anymore.

There should be helper functions to draw/process a button, draw/process a slider, etc. which presumably receive widget IDs as parameters (along with text, geometry, callback function pointers, etc.); you can do the same for composite or specialized widgets, and you can combine parent IDs and child IDs in case you process child widgets recursively, so what's the problem? Maybe that you are making lots of buttons, and you would be more comfortable with a retained mode GUI?

Omae Wa Mou Shindeiru

Yeah I already tried to say that the linenumber is useless for composite widgets that get called more than 1 time.

If you for example make a do_okcancel function you cant just let it use __LINE__ for the ok button and __LINE__+1 for the cancel button it calls, because when dialog1 and dialog2 both call that it wouldnt work then cause of same id on the second call.

Thats why I hinted already at using the parent id, because it should by definition be unique already, and mangling it with a hashfunction. Then you could call the ok button with gen_id(id,2,0) and the cancel button with gen_id(id,2,1) and it magically just works, if you found a good gen_id hashfunction.

A simple example would be like gen_id(id,n,i)=id*n+i but it only works if n is the global max for all i=(childwidgetindex inside a widget) in all widgets and its guaranteed that it never overflows and nowhere a conflicting id is generated. I would encourage you to find a better one yourself. (I currently use some other, but it is more complicated and in some aspects better, in others possibly worse.)

The ID is known at compile time, and in my case, I have a "std::vector<widget> DrawQueue" that I push widgets on with drawing information. I loop through this vector later at draw time for batching. This decouples the drawing and the interaction with the widget.

Nothing is stopping you from adding more data to the widget structure that gets added to the DrawQueue. A helper function could look for the widget with a certain ID and respond to whatever states are in that widget instance.

This topic is closed to new replies.

Advertisement