Allegro.cc - Online Community

Allegro.cc Forums » The Depot » example of a5 with an ImGui library

This thread is locked; no one can reply to it. rss feed Print
 1   2 
example of a5 with an ImGui library
gameovera
Member #15,340
October 2013

Hi all.

I write an example of a5 with ocornut/imgui(https://github.com/ocornut/imgui).

The code is here https://github.com/bggd/a5imgui_example

{"name":"CBUzrCFUcAAs5e5.png:large","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/4\/b427f12945e118eaa1429191eeb5af42.png","w":1024,"h":662,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/4\/b427f12945e118eaa1429191eeb5af42"}CBUzrCFUcAAs5e5.png:large

Thanks.

Thomas Fjellstrom
Member #476
June 2000
avatar

Hm, looks cool. Though I have to say, I'm not a fan of immediate mode guis :(

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Neuton Mouse
Member #15,146
May 2013
avatar

Yep, the gui looks decent enough to try. Might come handy in debugging.

SiegeLord
Member #7,827
October 2006
avatar

That's awesome :o.

Do we have a space somewhere to list these A5-using projects? Might be useful for the eventual frontpage redesign.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Elias
Member #358
May 2000

The obvious place would be the "resources directory" right here on this page... although I guess it hasn't been updated in a decade :p So maybe the wiki would be best instead? Or add it to liballeg.org. I think we should clean that up at some point, maybe move some old stuff like digmid, logos or humor to the wiki - and add more useful stuff like GUIs :)

--
"Either help out or stop whining" - Evert

kenmasters1976
Member #8,794
July 2007

I have to say it looks great, gonna give it a try.

Pho75_
Member #12,377
November 2010

Thanks for posting.

Interesting concept this immediate-mode GUI, I never heard of it before.
but I'm with Thomas, I think it falls down and gets cumbersome when GUI's get complex. :(
I don't think it makes GUI programming any easier as they propose.
It just seems to move managing widget state, layout, event stuff out of GUI library and makes it the programmers job to re-invent.

Reminds me of the unix dialog commandline utility.

Mark Oates
Member #1,146
March 2001
avatar

I've never heard of immediate mode GUIs but they sound like an interesting concept. It might be easy in some ways, but really limiting in others. This guy seems to be very pro immediate mode.

Pho75_ said:

It just seems to move managing widget state, layout, event stuff out of GUI library and makes it the programmers job to re-invent.

That's what came to my mind, too.

I wonder how everybody's GUIs are coming along these days. :)

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

jmasterx
Member #11,410
October 2009

I wonder how everybody's GUIs are coming along these days. :)

I still commit changes to my GUI as needed, and help people out that want to use it :) I get at least one email per month from people who want guidance on compiling or using it, so it seems useful for some projects other than my own. Factorio uses it too and it's doing very well so that's pretty gratifying :D

Since I ported my game to iOS, I added many touch-friendly features to Agui, like inertia scrolling, being able to scroll on anything that is already scrollable using your finger on the view, and some touch-compatibility stuff for events.

mmomar
Member #15,674
July 2014

Quote:
Pho75_ said:

It just seems to move managing widget state, layout, event stuff
out of GUI library and makes it the programmers job to re-invent.

That's what came to my mind, too.

You are seeing this from the wrong angle.

- You don't "move state out of the GUI library to the application [programmers job]". The point is to remove the idea itself of state duplication and state synchronization which makes retained-mode interfaces so painful to use. The only data that exists is the data that you own and you want to visualize or edit. The existence of data related to the UI library means more work and more bug.
So It is actually the opposite. Retained-mode libraries forces you to manage widget state. Immediate-mode interface tries to avoid you thinking about this at all.

- You don't "move event stuff out of the GUI library to the [programmers job]". You REMOVE the notion of events. They are extremely painful to handle in C/C++, a bit less-so with newly introduced C++11 lambda but still terrible. You need to declare functions, test things elsewhere, possibly in asynchronous context where you need to store and retrieve data to operate and react. It just leads to longer code and more bug.

How is that:

agui::Button button;
[...]
flow.add(&button);
button.setSize(80,40);
button.setText("Push Me");
button.addActionListener(&simpleAL);
[...]
//+ the code in the action listener (reacting to button, probably need to gather and update foreign state, maybe updating other widgets)

Spread in at least 3 locations of your code.

Going to be ever better than:

if (Button("Push me", ImVec2(80,40)) { /* do my stuff */ }

In a single location?

And this is a simple example because
- You only have 1 button. Imagine adding new members for every button, trying to name them, index or enum them.
- They are no user-state sync in example. If you start using anything that hold a value and you need your widget to mirror the state of your highly dynamic data and vice versa, you are in to a world of PAIN. Which imgui principles makes you avoid because only one copy of the data exist and you don't need to sync it.

Remaining is the problem of layout, and that has nothing to do with the library using a retained-facing interface vs a library using an immediate-facing interface. imgui is about the interface provided to the user. The library is free to remember your widgets and lay them out the way it is fit.

EDIT Not having to declare your widgets elevates debugging to a whole new level. With an implementation such as my ImGui above you can literally create a transient widget in the middle of some foreign left code that has nothing to do with interface, expose a local variable into a slider with 1 line of code. You can trace algorithm using ImGui::Text(), etc.

Mark Oates
Member #1,146
March 2001
avatar

jmasterx said:

like inertia scrolling, being able to scroll on anything that is already scrollable using your finger on the view, and some touch-compatibility stuff for events

Wow, you've gotten pretty far! You should post screenshots and stuff on your GitHub page (... wait, do people do that?). I still have a ways left to go on mine. A new bug was recently introduced that causes offscreen-rendered widgets to be drawn in all white... so not quite as exciting. :P

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

mmomar said:

Going to be ever better than:

if (Button("Push me", ImVec2(80,40)) { /* do my stuff */ }

In a single location?

gui.AddWidget(pushmebtn = new Button("Push me" , Area(0,0,80,40)));
//...
gui.HandleEvent(system->TakeEvent());
if (pushmebtn->Pushed()) {
   // do stuff
}

How is that so much more difficult? With your code you have to cram everything you want your widget to be into your constructor call.

And with your example I'm sure there is much more going on behind the scenes than you let on. For example style and drawing info has to come from somewhere.

And for example, how would an immediate mode gui handle dynamic layout? Ie. How does it handle movement and resizing of dynamic areas?

Elias
Member #358
May 2000

How would something like an editable text widget work? It has to remember line positions, cursor position, selection, scrollbar positions... is the user supposed to handle all of that?

--
"Either help out or stop whining" - Evert

mmomar
Member #15,674
July 2014

How is that so much more difficult?

You have two points of edit here definition vs use (instead of one), and often more with most implementation. And buttons is the simplest example since it doesn't carry state. How do you create a slider or checkbox that's in sync with some live game variables?

Quote:

you have to cram everything you want your widget to be into your constructor call.

The fact that I'm using constructors (and overloaded functions and different entry point for common variations) has doing to do with the imgui<>rmgui debate. You can use state or chained calls. I just choose what I thought was the easiest approach for my specific goal (aka hacking/auditing/debugging tools).

To take your example, a more imgui-like version might be:

gui.AddButton("Push me");
gui.SetArea(0,0,80,40);
if (gui.Pushed()) {
   // do stuff
}

The subtle but very important differences are 1) the lack of [...] so the code is in one place. 2) lifetime is defined by running code. What's lacking in your example is that good UI are dynamic. You want items to appear and disappear constantly, grey out, etc. You need to sync data with widgets. You have to maintain this UI somehow and the easiest way is to just "submit" UI based on your existing data.

Quote:

And with your example I'm sure there is much more going on behind the scenes
than you let on. For example style and drawing info has to come from somewhere.

Certainly, but that can be part of the UI state anyhow. I don't imagine it is the most common use to make every button unique, you want a consistent style so it is more likely to be decided at a more global "style" level.

By the way I don't claim that my implementation of an imgui is feature-ful in term of styling, it was designed for efficiency to run huge amount of tools for games. When you run a game on PS3/PS4 with tens of thousands of stuff going around and debuggers, profilers, etc. you can't afford UI overlay to be taking 3 ms to draw, so I designed ImGui carefully down to its visual to run optimally. New widget don't create additional draw calls, there's no dynamic allocation for the act of submitting or drawing widgets, etc. But you could design an imgui with more elaborate styling features.

Quote:

And for example, how would an immediate mode gui handle dynamic layout?

It's a wide question, but probably similarly to what a retained mode ui would. As long as the system is able to uniquely identify a widget you can do the same thing you would do with a retained-mode UI. If you really want features totally analogous to the typical layout features of say, css or most rmgui you can do a two-pass thing. However there's hundred of answers and ideas and techniques and helpers you can think of (the same goes for retained-mode UI, layout itself is a very open ended problem). My claim is that layout are better handled programatically with good helpers.

Quote:

Ie. How does it handle movement and resizing of dynamic areas?

I'm not sure what's the problem or question here.
You can try the demo here. http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20150321.zip

EDIT the system doesn't seem to allow me to reply twice.
Elias:
>How would something like an editable text widget work? It has to remember line positions, cursor position, selection, scrollbar positions... is the user supposed to handle all of that?

No of course that's the point. The GUI does that for you. For example in ImGui to create an edit control you can call this function:

ImGui::InputText("Name", &my_buf, 256);

It handle focusing, tabbing, selection, keyboard movement, copy/cut/paste, undo/redo. I don't have a multi-line text edition in there yet, probably will do one at some point.

jmasterx
Member #11,410
October 2009

I certainly see the value in it for rapid tool development on a platform like Ps4, XBone, etc.

I'm still not convinced I would want to use it in a project like my game. I have some very custom behaviors that I want out of my Widgets:

For example, some of my TextBoxes, when text is appended to them, they scroll to the bottom no matter what. For my chat boxes, if the user has scrolled up to look at old chat, I just silently append new chat, and only scroll automatically if the scrollbar is at the bottom.

For my needs, I also needed to have colored text, and what's more, my textbox can parse text using custom rules (unfortunately not yet using regular expressions) and it will put out events for specific rules. For example, I can create a rule called "url" and it will detect when the user hovers a url and give me an action for that.

It's reasons like this that I wrote my own rm gui in the first place.

I have several other areas where I required much more than what standard gui events offered and I doubt it would be particularly easy for an im gui to deal with these feature requests.

That said, I think for the reasons you mentioned, I see the value in it, it seems useful for rapid tool development. But for a massive gui-oriented project like mine, I think mixing logic and presentation would lead to an ugly code base. I would probably have to subclass many widgets to get what I want too.

As for the argument of a single button or single style, if you're developing a game, I highly doubt you will only have just one button. I have 4 in mine. One of which only does circle collision detection.

Players demand more and more and developers have to keep up, it is not unreasonable to want different style buttons in a game.

Another issue I see is when I click a button and each time, a new one pops up. I have no choice but to maintain an array, and possibly retain all the attributes for each custom button, so basically I end up having to create a custom copy of the state.

In my game, every server can have an indeterminable amount of tables (they are Widgets) and each table has 4 chairs. Every chair has custom rendering to render a player's name and avatar on the chair.

The player can filter certain tables based on criteria. Tables not matching the criteria must be darkened.

That seems like a lot of state that I think an imgui might have trouble with. It can be done with imgui but it seems impractical to do so.

I see the value of imgui as I said before, only for rapid tool development, and not for a practical large game project.

My game raised a lot of GUI-related challenges for me that I'm not sure I could have solved [elegantly] without having written my own API.

I might be wrong though and imguis might be practical for large game projects. If you can solve the issues I listed above I would be very interested in hearing those solutions.

mmomar
Member #15,674
July 2014

I appreciate and understand the need to have custom UI behaviors and rewriting your own UI. Even more so for your own game! (the same way I wouldn't advise using GTK/QT for a game that wouldn't be flexible enough).
But again this has nothing to do with the rmgui/imgui debate.
A lot of your example seem to imply that the feature would be necessarily harder to implement with an imgui.

e.g.

jmasterx said:

For example, some of my TextBoxes, when text is appended to them, they scroll to the bottom no matter what. For my chat boxes, if the user has scrolled up to look at old chat, I just silently append new chat, and only scroll automatically if the scrollbar is at the bottom.

This is already possible in mine and actually happen to be done in one of the ui demo, so as colored text. If you want to parse URL within a text box and display a menu on click I'm sure you could do that as well (in neither ui it would be provided as default). But I imagine you'd want some sort of markup language that's applied globally rather than just in a text box.

My approach for customization is that I see ImGui as a basic set of helpers, you can combine the lower-level helpers to create custom widgets.

Quote:

As for the argument of a single button or single style, if you're developing a game, I highly doubt you will only have just one button. I have 4 in mine. One of which only does circle collision detection.

Of course, but I meant the 4 styles are probably defined somewhere globally rather than in each button. So all the styling settings (which can be dozens of parameters) won't be specified for each button. You would rather have an approach like:

Button("OK", style)

Rather than the unpractical:

Button("OK", five millions style parameters).

In ImGui the style is part of the state (akin to OpenGL), so you can do:

PushStyleCol(ImGuiCol_Button, ImColor(1.f,0.f,1.f));
PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
Button()
Button()
etc.

Which if you start using often would probably lead you to create helpers,

PushMyStyleB()
Button()
Button()
PopMyStyleB()

I don't quite follow the problem with your examples.

>In my game, every server can have an indeterminable amount of tables (they are Widgets) and each table has 4 chairs. Every chair has custom rendering to render a player's name and avatar on the chair.
>The player can filter certain tables based on criteria. Tables not matching the criteria must be darkened.

It seems like all that would be easier done with an imgui style library, since all you have to do if you reflect the state of your server/game state. But I'm not sure what you mena by "tables" and "chairs" and if those are UI elements or sprite/3d objects.

I routinely display and filter thousands of active dynamic items with ImGui with no issue. I suppose it depends on the implementation (mine tries to be fast) rather than the interface paradigm. What's guaranteed is that you would have a hard time displaying a list of 10 million item with an rmgui whereas you can do it with an imgui because the objects don't need to exist or be stored anywhere. You can even seek according to your current scrolling and just display what you need.

jmasterx
Member #11,410
October 2009

Those are some good points, I'll want to have a further look at some of your examples. Do you know of any large open sourced games that use imgui? I would be very curious to see the structure of the code. It worries me to mix presentation with logic, but I might not be thinking outside the box.

This is what I meant about the tables and chairs:
{"name":"609365","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/4\/a4bbc19720bf2cd1274da487fdf3627a.png","w":663,"h":392,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/4\/a4bbc19720bf2cd1274da487fdf3627a"}609365

Every chair can be clicked, and every table can be clicked. The tables have custom text that changes based on the type of game. Both the Chair and Table subclass Button (but that does not count toward my 4 button styles).

I do all my gui hookup work in scene begin event of my game:

#SelectExpand
1void LobbyScene::sceneBegin() 2 { 3 m_gear = getDeviceManager()->getSpriteManager()->getImage("gear"); 4 getDeviceManager()->getShared()->setPlannedDisconnection(false); 5 addProvider(getDeviceManager()->getLobbyNetHandler()); 6 addProvider(this); 7 8 m_termsDialog = new TermsDialog(&getGuiFactory()); 9 addProvider(m_termsDialog); 10 m_viewProfileDialog = new ViewProfileDialog(&getGuiFactory()); 11 m_lobbyContainer = new LobbyContainer(&getGuiFactory(), 12 getDeviceManager()->getLanguageManager()); 13 getGui().add(m_lobbyContainer->getWidget()); 14 addListener(m_lobbyContainer); 15 16 m_accountSettingsDialog = new AccountSettingsDialog(&getGuiFactory()); 17 addProvider(m_accountSettingsDialog); 18 _addSceneEventProvider(m_accountSettingsDialog); 19 20 m_reportDialog = new ReportDialog(&getGuiFactory()); 21 addProvider(m_reportDialog); 22 _addSceneEventProvider(m_reportDialog); 23 24 m_selectionDialog = new AvatarSelectionDialog(&getGuiFactory(),getDynamicUIManager()->getAvatarCache()); 25 addProvider(m_selectionDialog); 26 _addSceneEventProvider(m_selectionDialog); 27 28 m_leaderboardDialog = new LeaderboardDialog(&getGuiFactory()); 29 addProvider(m_leaderboardDialog); 30 31 m_paymentDialog = new PaymentDialog(&getGuiFactory()); 32 addProvider(m_paymentDialog); 33 34 m_lobbyChange = new LobbyChangeDialog(&getGuiFactory()); 35 m_lobbyChange->setCurrentAddressAndPort(getDeviceManager()->getNetClient()->getAddress(), 36 getDeviceManager()->getNetClient()->getPort()); 37 addProvider(m_lobbyChange); 38 39 m_friendLobbyChange = new FriendLobbyChangeDialog(&getGuiFactory()); 40 m_friendLobbyChange->setCurrentAddressAndPort(getDeviceManager()->getNetClient()->getAddress(), 41 getDeviceManager()->getNetClient()->getPort()); 42 addProvider(m_friendLobbyChange); 43 44 m_themeDialog = new ThemeSelectionDialog(&getGuiFactory(),getDynamicUIManager()->getThemeManager()); 45 addProvider(m_themeDialog); 46 _addSceneEventProvider(m_themeDialog); 47 48 m_chatList = new ChatListHandler(&getGuiFactory()); 49 _addSceneEventProvider(m_chatList); 50 addProvider(m_chatList); 51 _createGroups(m_chatList); 52 53 int limit = 220; 54 if(Platf::isRetina()) 55 { 56 limit *= 1.25f; 57 } 58 59 m_lobbyContainer->addOuter(m_chatList->getContainer(),agui::BorderLayout::WEST); 60 61 m_lobbyContainer->getOuter()->setBorderMargin(agui::BorderLayout::WEST,limit); 62 63 m_lobbyChat = new LobbyChatWidget( 64 getDeviceManager()->getLanguageManager(), 65 getDeviceManager()->getFontManager(),&getGuiFactory(),&getGui(),getDeviceManager()->getCensor()); 66 addDynamicElement(m_lobbyChat); 67 _addSceneEventProvider(m_lobbyChat); 68 addProvider(m_lobbyChat); 69 m_lobbyContainer->addOuter(m_lobbyChat->getWidget(),agui::BorderLayout::EAST); 70 m_lobbyContainer->getOuter()->setBorderMargin(agui::BorderLayout::EAST,limit); 71 72 m_lobbyTableManager = getGuiFactory(). 73 createLobbyTableManager(getDeviceManager()->getSpriteManager(), 74 getDynamicUIManager()->getBackgroundManager(),&getGui(),getDynamicUIManager()->getAvatarCache(),getDynamicUIManager()->getThemeManager()); 75 addProvider(m_lobbyTableManager); 76 _addSceneEventProvider(m_lobbyTableManager); 77 78 addDynamicElement(m_lobbyTableManager); 79 m_lobbyContainer->addInner(m_lobbyTableManager,agui::BorderLayout::CENTER); 80 81 m_contextHandler = new LobbyContextHandler(&getGuiFactory(), 82 getDeviceManager()->getLanguageManager(),&getGui(),getDeviceManager()->getShared()->getSettingsManager()); 83 addProvider(m_contextHandler); 84 85 m_filterManager = new LobbyFilterManager(&getGui(),&getGuiFactory(),getDeviceManager()->getLanguageManager() 86 ,getDeviceManager()->getColorManager(), getDeviceManager()->getFontManager()); 87 _addSceneEventProvider(m_filterManager); 88 addProvider(m_filterManager); 89 m_lobbyContainer->setFilterManager(m_filterManager); 90 m_filterManager->reapplyTableFilters(); 91 92 m_lobbyContainer->addInner(m_filterManager->getWidget(),agui::BorderLayout::SOUTH); 93 m_lobbyContainer->getInner()->setBorderMargin(agui::BorderLayout::SOUTH, 94 0); 95 addDynamicElement(m_lobbyContainer); 96 97 //NAVIGATION STUFF 98 m_navigation = new NavigationBar(&getGuiFactory(), 99 getDeviceManager()->getLanguageManager(),getSceneMessenger(), 100 getDeviceManager()->getDisplay(),getDeviceManager()->getAudioManager(),this); 101 102 _addSceneEventProvider(m_navigation->getIOButton()); 103 _addSceneEventProvider(m_navigation->getIOButton()->getSoundOptions()); 104 105 m_navigation->getWidget()->setSize(0,m_navigation->getHeight()); 106 m_lobbyContainer->addOuter(m_navigation->getWidget(),agui::BorderLayout::NORTH); 107 108 m_navigation->getSelfButton()->addActionListener(this); 109 m_navigation->getSelfButton()->setText(getDeviceManager()->getShared()->getPlayerManager()->getSelfPlayer()->getUsername()); 110 int curSelfH = m_navigation->getSelfButton()->getHeight(); 111 m_navigation->getSelfButton()->resizeToContents(); 112 m_navigation->getSelfButton()->setSize(m_navigation->getSelfButton()->getWidth(),curSelfH); 113 m_navigation->getSelfButton()->setToggleButton(true); 114 115 m_navigation->setLobbyName(getDeviceManager()->getShared()->getLobbyName()); 116 117 addProvider(m_navigation->getLobbyCoinDisplay()); 118 119 m_selfMenu = getGuiFactory().createPopUpMenu(); 120 m_selfMenu->setInvokeButton(m_navigation->getSelfButton()); 121 m_viewProfileItem.setText(getDeviceManager()->getLanguageManager()->getElement("self.view.profile")); 122 m_editProfileItem.setText(getDeviceManager()->getLanguageManager()->getElement("self.edit.profile")); 123 m_selectAvatarItem.setText(getDeviceManager()->getLanguageManager()->getElement("select.avatar")); 124 m_signoutItem.setText(getDeviceManager()->getLanguageManager()->getElement("signout.title")); 125 m_selfMenu->addItem(&m_viewProfileItem); 126 m_selfMenu->addItem(&m_editProfileItem); 127 m_selfMenu->addItem(&m_selectAvatarItem); 128 m_selfMenu->addItem(&m_signoutItem); 129 m_selfMenu->addActionListener(this); 130 m_navigation->getSelfButton()->addMouseListener(this); 131 m_navigation->getSelfButton()->setFocusable(false); 132 m_navigation->getAvatarButton()->addActionListener(this); 133 m_navigation->getLeaderboardButton()->addActionListener(this); 134 m_navigation->getThemeButton()->addActionListener(this); 135 m_navigation->getBuyButton()->addActionListener(this); 136 m_navigation->getIOButton()->setWantReportItem(true); 137 m_navigation->getIOButton()->setActionListener(this); 138 m_navigation->getLobbyChangeButton()->addActionListener(this); 139 m_navigation->getFindFriendsButton()->addActionListener(this); 140 141 //END NAV STUFF 142 143 m_host = new HostGameDialog(&getGuiFactory(), 144 getDeviceManager()->getLanguageManager(),getDeviceManager()->getColorManager(), 145 getDeviceManager()->getFontManager()); 146 147 addProvider(m_host); 148 _addSceneEventProvider(m_host); 149 150 m_inviteNotifyHandler = new NotificationHandler( 151 &getGuiFactory(),m_navigation->getInviteButton(),&getGui()); 152 m_inviteNotifyHandler->setHandlingInvites(true); 153 154 getGui().add(m_inviteNotifyHandler->getWidget()); 155 addProvider(m_inviteNotifyHandler); 156 157 m_navigation->getBackButton()->addActionListener(this); 158 159 linkListeners(); 160 161 DISPATCH_SCENE_EVENT 162 (*it)->loadSettings(getDeviceManager()->getShared()); 163 164 //for now put it here 165 if(getDeviceManager()->getShared()->getLobbyCache()->needsFullUpdate()) 166 { 167 DISPATCH_LOBBY_EVENT 168 (*it)->readyForLobbyData(); 169 170 getDeviceManager()->getShared()->getLobbyCache()->setNeedsFullUpdate(false); 171 } 172 else 173 { 174 DISPATCH_LOBBY_EVENT 175 (*it)->updateLobbyFromCache(); 176 } 177 178 std::vector<int> tableFees = getDeviceManager()->getShared()-> 179 getLobbyCache()->getTableFees(); 180 181 int highStakes = getDeviceManager()->getShared()->getLobbyCache()->getHighStakesVal(); 182 183 std::vector<int> minRatings = getDeviceManager()->getShared()->getLobbyCache()->getMinRatingValues(); 184 185 if(tableFees.size() > 0) 186 { 187 receiveFeeOptions(tableFees,minRatings,highStakes); 188 } 189 190 showQueuedMessageBoxes(); 191 showQueuedRequests(); 192 193 if(getDeviceManager()->getShared()->needToShowPayment()) 194 { 195 getDeviceManager()->getShared()->setShowPayment(false); 196 DISPATCH_LOBBY_EVENT 197 (*it)->requestCoinsDialog(); 198 } 199 200 setStringSetting("user.name",getDeviceManager()->getShared()->getPlayerManager()->getSelfPlayer()->getUsername()); 201 getDeviceManager()->getShared()->getSettingsManager()->setBoolSetting("welcome",false); 202 }

mmomar
Member #15,674
July 2014

You can check the demo linked above, the entirely of the features in the demo are done from a function called void ImGui::ShowTestWindow(). It's a long function because it's showing a lot of features individually.

https://github.com/ocornut/imgui/blob/master/imgui.cpp#L9219

I don't really know the state of open-source games, been developing proprietary console games for a long time now. I intend to replace the old horrible horrible UI for my emulator Meka (using Allegro, mostly done in 1998-1999!) with ImGui so perhaps that'll be a demo. But the demo above has a fair amount of stuff.

I'm not sure your table/chairs are really "UI" in the classic widgety sense, it's more general programming with visuals and interactions and animations. If you start to desire detailed interactive animations you want to manipulate state that's not gonna be part of any "ui" engine. e.g. the position of your character, where they are looking, the position of the cards while they fly off the table. If you try to retrofit this data in a generic way in your ui library it'll feel awkward and constrained in the first place, so it's perfectly reasonable to do something custom but I don't think that custom thing classify as a UI library.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

mmomar said:

I'm not sure what's the problem or question here.
You can try the demo here.
http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20150321.zip

My laptop only has DX9 or 10? with Vista and only has OpenGL 2. So all four demo programs crash for me. The DX ones are both missing a dll, and the OpenGL 3 one fails to load an extension and the OpenGL one just crashes.

mmomar
Member #15,674
July 2014

Well that's very interesting, I suppose I need to test on Vista but Visual Studio 10 should make stuff that are Vista/XP compatible (the later is disabled by default in the option). This is the first time I hear of a crash but usually people build themselves. Because the DX9 demo and OpenGL 2 demo should work on old hardware. Thanks!

(Which DLL are missing for DX9? Don't you have DX9 runtime installed?
If you have time to try the .sln project it would be helpful. But I'll inspect.)

gameovera
Member #15,340
October 2013

The demo is not wait in the game loop. it is high load for an laptop's iGPU probably.

mmomar
Member #15,674
July 2014

Yes because I'm using it to measure performance so it runs with no limit.
I should add a wait/VSync option on by default, and make unthrottled an option. Thanks!

By the way, the Unity editor UI is essentially an imgui api
http://docs.unity3d.com/ScriptReference/EditorGUI.FloatField.html

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I was missing d3dx9_43 or something like that.

I got imgui and its opengl example program built after compiling glfw. It's very impressive what you can do with immediate mode guis. One thing , how do you handle input and events? And where do you store your data? You can't just pass everything into the function or that defeats the purpose. Is your style global state that gets copied into every object as it is at the time the object was created?

11,000 lines is a lot to cram into one source file, and the widget constructors are a bit out of control :

#SelectExpand
1 2 // Widgets 3 IMGUI_API void Text(const char* fmt, ...); 4 IMGUI_API void TextV(const char* fmt, va_list args); 5 IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); 6 IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args); 7 IMGUI_API void TextWrapped(const char* fmt, ...); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos(); 8 IMGUI_API void TextWrappedV(const char* fmt, va_list args); 9 IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, recommended for long chunks of text 10 IMGUI_API void LabelText(const char* label, const char* fmt, ...); // display text+label aligned the same way as value+label widgets 11 IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args); 12 IMGUI_API void Bullet(); 13 IMGUI_API void BulletText(const char* fmt, ...); 14 IMGUI_API void BulletTextV(const char* fmt, va_list args); 15 IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0), bool repeat_when_held = false); 16 IMGUI_API bool SmallButton(const char* label); 17 IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); 18 IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); 19 IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,1), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding 20 IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false); 21 IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); // adjust display_format to decorate the value with a prefix or a suffix. Use power!=1.0 for logarithmic sliders 22 IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); 23 IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); 24 IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); 25 IMGUI_API bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians 26 IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f"); 27 IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format = "%.0f"); 28 IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format = "%.0f"); 29 IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format = "%.0f"); 30 IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); 31 IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); 32 IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float)); 33 IMGUI_API void PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); 34 IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float)); 35 IMGUI_API void PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); 36 IMGUI_API bool Checkbox(const char* label, bool* v); 37 IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); 38 IMGUI_API bool RadioButton(const char* label, bool active); 39 IMGUI_API bool RadioButton(const char* label, int* v, int v_button); 40 IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); 41 IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1, ImGuiInputTextFlags extra_flags = 0); 42 IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision = -1); 43 IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision = -1); 44 IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision = -1); 45 IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0); 46 IMGUI_API bool InputInt2(const char* label, int v[2]); 47 IMGUI_API bool InputInt3(const char* label, int v[3]); 48 IMGUI_API bool InputInt4(const char* label, int v[4]); 49 IMGUI_API bool Combo(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1); 50 IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items = -1); // separate items with \0, end item-list with \0\0 51 IMGUI_API bool Combo(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); 52 IMGUI_API bool ColorButton(const ImVec4& col, bool small_height = false, bool outline_border = true); 53 IMGUI_API bool ColorEdit3(const char* label, float col[3]); 54 IMGUI_API bool ColorEdit4(const char* label, float col[4], bool show_alpha = true); 55 IMGUI_API void ColorEditMode(ImGuiColorEditMode mode);

It's a little tedious to learn all the different function signatures for your widgets. It would be far easier to have a single default constructor function, wouldn't it? In my gui I plan to have a widget factory. You just pass in a string, and it deciphers the widget and any attributes set. Users can create their own widget factories through callback or forwarding functions.

One other thing, how would you go about implementing a program like this, with dynamic resizing (you can resize the window by any corner and middle click drag the window (I mean the orange bordered object) as well as resize the inner cells through their splitter handles (hover with the mouse and press the button grid to change the pointer)) :
EagleTest.7z

{"name":"609369","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/2\/62c18959c8c36535419444ea4f2dab5a.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/2\/62c18959c8c36535419444ea4f2dab5a"}609369

I've attached the source for the program here :
GuiTestMain.cpp

Edit
The function being run is GuiTestMain2 to be specific.

mmomar
Member #15,674
July 2014

Thanks for looking into it!

One thing , how do you handle input and events?

Not sure exactly at which level you are talking about. ImGui receives inputs from the application (e.g. mouse position, mouse buttons, keyboard state) and stores that.

Everything is processed as you call the function. ImGui maintains what's the 'cursor position' (the current layout position). When you call Button(), it calculate the bounding box of the button in the screen, and test e.g. if the mouse is hovering the button, then it can react to mouse inputs. If the mouse is clicking in this area we return true. Aside from that it pushes vertices into buffer that can be rendered later (this buffer will present the entire UI rendering). And it moves the cursor, e.g.: to the next line.

That's actually a very simplified version of what's actually happening, because there's lots of details under the hood. But it doesn't "store" data per widget or very rarely. The only data that's stored is the transient render data that it pushes and gets batch-drawn at the end of the frame, basically a bunch of textured triangles. It doesn't render immediately to allow merging draw calls for efficiency and also because not touching the render immediately allows you to use ImGui within your own engine rendering to debug it.

ImGui infer an unique identifier per widget, based on the stack of items, labels and other information. A button press is actually press+release so that happens over multiple frames, that's where the unique identifier comes in. When you click the button I store the unique identifier into a variable, 'ActiveID'. Next frame if you release the mouse while hovering the button with the same identifier it knows that you pressed and clicked on the same button and that's where it returns true.

If you have time to get into details, any of those 4 articles should give you a better understanding at how it works:
https://github.com/ocornut/imgui#references

Quote:

And where do you store your data? You can't just pass everything into the function or that defeats the purpose. Is your style global state that gets copied into every object as it is at the time the object was created?

Neither those questions really apply. There's no "object", they don't exist. When you call Button() it handles the "logic" of a button and push triangles to render the button, but the button doesn't exist anywhere. There's no "Button" struct.

There are things that are stored. For example, when you click a tree node to open/collapse it, it stores a boolean that associated to the ID of that tree node. Resizeable column stores a float (associated to the ID of that columns). But those storage that persist for more than 1 frame are actually rather infrequent. Stuff like text editing information (e.g. cursor position), there's only one of them, since by definition you can't type into 2 text fields simultaneously.

Btw I think it's probably a little harder to write a great imgui-type library rather than write a great rmgui-type library (even if both are hard). But I believe it's so much better for the user so it's worth doing it.

Quote:

11,000 lines is a lot to cram into one source file, and the widget constructors are a bit out of control :

Number of line is a stylistic choice. The number 1 priority for ImGui was to be ultra-portable and not necessitate a lot of custom-building-setup. Librairies are a PAIN to deal with under Windows and it's frequent that people give up using a library just because it doesn't build, doesn't link, have conflict with standard libs variants, etc.. It's hell. So by providing one single .cpp file and no build file (only the examples have build files, not the library), the message is: you can copy this into your folder and it'll just build.

Contrast that to any major library (e.g. Allegro) that are not easy to build. Unfortunately it's probably impossible to solve this problem well for big libraries. It's a really hard issue with no clear "winning answer". Developers are already spending a lot of time improving their portable build process (like Allegro did) but it is such a time-sink full of hazard and not the most exciting feature to work on.

For a small library shipping with no dependency like ImGui it's possible to just avoid the building issue. Similarly to the STB library with all fit into a single .h file (image loader, ttf loader, ogg loader, scripting languages, compressors, voxel renderer..)
https://github.com/nothings/stb/

Quote:

and the widget constructors are a bit out of control

I disagree ;)
The easiest (until I get to write better web documentation) is to browse the ShowTestWindow() function.

Quote:

It would be far easier to have a single default constructor function, wouldn't it?

No because the parameters are tailored and make sense only in the context of a specific widget.

Quote:

In my gui I plan to have a widget factory. You just pass in a string, and it deciphers the widget and any attributes set.

Using strings to pass variable numbers of argument and named variables is a useful pattern in C/C++ for this sort of situation, that would work. This is what AntTweakBar used. The reason ImGui's isn't doing that is that it's hard to construct settings dynamically with strings. However I use format strings extensively (they are very powerful).

Quote:

One other thing, how would you go about implementing a program like this, with dynamic resizing (you can resize the window by any corner and middle click drag the window (I mean the orange bordered object) as well as resize the inner cells through their splitter handles (hover with the mouse and press the button grid to change the pointer)) :

To answer your question about mimicing the example: you can't exactly do that at the moment. I haven't added movable horizontal separators yet. It has resizeable columns but they are vertical and don't have the exact same properties you'd expect for this sort of setup. To-do list is enormous but I'll let you know when I sort that out. It's a good example to try to mimic. Thanks!

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

mmomar said:

A button press is actually press+release so that happens over multiple frames, that's where the unique identifier comes in.

In my gui I only look for a button press, not a release. I could change it, but I don't know, I like the immediacy of the button press, instead of a 2 step process.

Quote:

If you have time to get into details, any of those 4 articles should give you a better understanding at how it works:

I'll take a closer look some time.

It's very interesting to remove the data from the widgets, but in some cases doesn't that make it the users job to store the data?

How do you control your layout in imgui? It is just a single global flow layout that all the widgets use? Or do you have others, and if so, are they difficult to create in imgui?

 1   2 


Go to: