![]() |
|
Best way to abstract allegro events for my gui library |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
So like the title says, I am trying to figure out the best method to abstract Allegro 5's event system into my own event system for use with my GUI. My GUI also needs to be compatible with other libraries like SDL / SFML / what the hell ever else someone wants a port of.... as well. So, my first thought is to duplicate Allegro, so that A5 users don't have to adjust much to use my GUI's event system. This would mean copying most ALLEGRO_EVENT_BLAH_BLAH into EAGLE_EVENT_BLAH_BLAH and duplicating the event union and structures. The main focus right now is to get the abstraction ready, so I can fill in the backend for Allegro 5 and start porting all my widgets to the new library. So, any ideas / tips / helpful comments? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Arthur Kalliokoski
Second in Command
February 2005
![]() |
Consider having several event loops, whether the gui is active or not could select one specialized for the gui, another could be for game movement keys, whatever. They all watch too much MSNBC... they get ideas. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Does anybody have any ideas for abstracting graphics libraries? I know theres AGUI, who wrote that again? Here's what my gui looks like now, with A4 driving it : Do you like the way it looks? What options should a user have when drawing widgets in a gui library? What is the best way to integrate layout managers? Give every widget handler (frame / window / subwindow) a layout manager? So - thoughts? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
axilmar
Member #1,204
April 2001
|
Edgar Reynaldo said: So, any ideas / tips / helpful comments? The best way to deal with it is to create one event for Allegro, named CAllegroEvent or whatever your naming convention is. This event will not be available to your users though, unless they explicitly process it. Your event loop will catch this event and create other events for the GUI, like mouse down/mouse up, mouse/move etc. In this way, you can put other event systems in, if you wish. For example, you could have an CWin32MessageEvent for all Win32 messages, and then have your GUI create the same mouse down/up/move etc events that are also created for CAllegroEvent. Edgar Reynaldo said: Does anybody have any ideas for abstracting graphics libraries? Provide a CCanvas class with drawing methods, selecting pens and brushes, etc. Then let widgets draw to that. Quote: Do you like the way it looks? I'll be honest: I don't like it very much. Quote: What options should a user have when drawing widgets in a gui library? The user should be allowed to skin widgets, i.e. select all its graphical aspects at runtime. Quote: What is the best way to integrate layout managers? Give every widget handler (frame / window / subwindow) a layout manager? Create widgets for layout, i.e. integrate the layout mechanism with widgets. Each widget should have its own layout, and a special group of your widgets will be about layout only. Using a secondary tree of layout objects makes it more difficult to create layouts. |
Elias
Member #358
May 2000
|
axilmar said: Using a secondary tree of layout objects makes it more difficult to create layouts. I'd say that's the same mistaken believe which makes CSS as hard as it is. <table><tr><td> elements in HTML are extremely simple, everyone can for example make a 3 column layout in a minute. CSS on the other hand is not simple at all, a 3 column layout requires hours of research. -- |
Thomas Fjellstrom
Member #476
June 2000
![]() |
I haven't really found a simpler/better method of widget layouts than what Qt uses. Other than explicit widgets that layout their children. axilmar said: Provide a CCanvas class with drawing methods, selecting pens and brushes, etc. Then let widgets draw to that. I do something similar for my little Canva5 library. I used Qt's setup as an example, so its fairly similar: http://git.tomasu.org/canva5.git/blob/refs/heads/prototype:/core/src/Display.cpp I rather like it. All I have to do is implement a new Bitmap class and a new Display class, and a new PaintEngine class and the lib is instantly ported to another backend. append: One of these days I intend on adding some GUI classes to it. But it can be used as an engine for 2d games quite nicely. Just spam some Item's of various types at the Model, and it'll take care of everything for you. You can even create multiple views into the same world! It's really quite neat. -- |
Luiji99
Member #12,254
September 2010
|
I really like the Qt/GTK+ design. It requires much less compile-and-test sequences since most of the layout is calculated automatically. The alternative would be a GUI designer, but I tend to find WYSIWYG output hideous. Programming should be fun. That's why I hate Java. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
axilmar said: I'll be honest: I don't like it very much. Being honest doesn't help much if you are not also useful..... What is it you do not like? What exactly is this QT style that you all mention? I am not familiar with their source code or programming with their library... Also, what kind of interface do you like? Constructors with every parameter possible, or basic constructors and specialized setup functions....??? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Thomas Fjellstrom
Member #476
June 2000
![]() |
Edgar Reynaldo said: What exactly is this QT style that you all mention? I am not familiar with their source code or programming with their library... It provides a dynamic layout mechanism. For the most part there is no hand placement of widgets. Quote: Also, what kind of interface do you like? Constructors with every parameter possible, or basic constructors and specialized setup functions....??? I'd go with simple ctors and a bunch of methods. -- |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Thomas Fjellstrom said: It provides a dynamic layout mechanism. For the most part there is no hand placement of widgets. Moose, you are referring to the somewhat javax / swing type widget layout mechanisms? Where you provide a window / container with a layout widget? I will be providing layout widgets this time, the widget handlers will own a layout manager, whether a dumb default one where you can hand place widgets or a smart one that lays out and resizes to fill / fit / align / whatever else you want..... Quote: I'd go with simple ctors and a bunch of methods.
I think this is simpler and better too. More like Javax and AWT. That way you don't have to memorize long constructor parameters. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
jmasterx
Member #11,410
October 2009
|
Edgar Reynaldo said: I know theres AGUI, who wrote that again? I wrote Agui. Agui GUI API -> https://github.com/jmasterx/Agui |
Thomas Fjellstrom
Member #476
June 2000
![]() |
Edgar Reynaldo said: Moose, you are referring to the somewhat javax / swing type widget layout mechanisms? Where you provide a window / container with a layout widget? I will be providing layout widgets this time, the widget handlers will own a layout manager, whether a dumb default one where you can hand place widgets or a smart one that lays out and resizes to fill / fit / align / whatever else you want..... Qt has a special layout object you assign to widgets, any widgets. But dedicated layout widgets also work. Same idea. Just so long as you don't force me to layout my gui by hand, I won't hate you. -- |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
jmasterx said: I wrote Agui. Ah, jmasterx, there you are. So how did you achieve your abstraction of the graphics backend in your library agui? Virtual systems? What is your opinion on my gui and what do you think I should work on with it? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
jmasterx
Member #11,410
October 2009
|
Since Agui favors Listeners over bubbling messages, the way I did it might not be exactly what you need (since I think you mentioned integrating your messages?) But here is basically how I did it. I have a base class Image, Font, Font Loader, Image Loader, Graphics Context... I expect the back-end to implement all of these. The loaders are pretty straight forward: class AGUI_BACKEND_DECLSPEC Allegro5FontLoader : public FontLoader { public: Allegro5FontLoader(void) {} ~Allegro5FontLoader(void) {} virtual Font* loadFont(const std::string &fileName, int height); }; They implement the base class's load method and return an abstract Font, Image, etc. The way Input works is as follows. The Input Handler base looks like: 1namespace agui
2{
3
4 /**
5 * Abstract class for Input.
6 *
7 * Should implement:
8 *
9 * A method to receive a back end specific event and convert it
10 * to MouseInput or KeyboardInput.
11 *
12 * getTime (default uses std::clock)
13 *
14 * Should respect:
15 *
16 * isMouseEnabled
17 *
18 * isKeyboardEnabled
19 * @author Joshua Larouche
20 * @since 0.1.0
21 */
22
23 class AGUI_CORE_DECLSPEC Input
24 {
25 double startTime;
26 std::queue<MouseInput> mouseEvents;
27 std::queue<KeyboardInput> keyboardEvents;
28 bool mouseEnabled;
29 bool keyboardEnabled;
30 protected:
31 /**
32 * Default constructor.
33 */
34 Input(void);
35 public:
36 /**
37 * Called by the Gui in its logic loop. Used for non event driven back ends.
38 */
39 virtual void pollInput();
40 /**
41 * Pushes a mouse event which will be dequeued and processed in the next logic loop.
42 */
43 void pushMouseEvent(const MouseInput &input);
44 /**
45 * Pushes a keyboard event which will be dequeued and processed in the next logic loop.
46 */
47 void pushKeyboardEvent(const KeyboardInput &input);
48 /**
49 * @return True if no mouse events are queued.
50 */
51 bool isMouseQueueEmpty() const;
52 /**
53 * @return True if no keyboard events are queued.
54 */
55 bool isKeyboardQueueEmpty() const;
56 /**
57 * Called by the Gui to process the event.
58 * @return The keyboard event information and removes it from the queue.
59 */
60 const KeyboardInput dequeueKeyboardInput();
61 /**
62 * Called by the Gui to process the event.
63 * @return The mouse event information and removes it from the queue.
64 */
65 const MouseInput dequeueMouseInput();
66 /**
67 * @return The amount of time the application has been running in seconds.
68 */
69 virtual double getTime() const;
70 /**
71 * Set whether or not keyboard input is enabled for the Gui.
72 */
73 void setKeyboardEnabled(bool enabled);
74 /**
75 * Set whether or not mouse input is enabled for the Gui.
76 */
77 void setMouseEnabled(bool enabled);
78 /**
79 * @return True if mouse input is enabled for the Gui.
80 */
81 bool isMouseEnabled() const;
82 /**
83 * @return True if keyboard input is enabled for the Gui.
84 */
85 bool isKeyboardEnabled() const;
86 /**
87 * Default destructor.
88 */
89 virtual ~Input(void);
90 };
91}
The way this works is, there is a Gui object that handles just about everything event related. It takes in an Input and GraphicsContext. 1class Scene : public agui::ActionListener, public agui::WidgetListener,
2 public SceneEventProvider
3 {
4 Timer* m_gameTimer;
5 DeviceManager* m_settings;
6 DynamicUIManager* m_dynamicUI;
7 SceneManagerMessage* m_sceneMessenger;
8
9 agui::Gui m_gui;
10 agui::Allegro5Input m_a5GuiInput;
11 agui::Allegro5Graphics m_a5GuiGraphics;
12 agui::Allegro5CursorProvider m_a5GuiCursor;
13.....
14
15 Scene::Scene(void)
16 : m_gameTimer(NULL),
17 m_sceneMessenger(NULL),
18 m_settings(NULL),
19 m_frame(NULL)
20 {
21 m_gui.setInput(&m_a5GuiInput);
22 m_gui.setGraphics(&m_a5GuiGraphics);
23 m_gui.setCursorProvider(&m_a5GuiCursor);
24 m_gui.setToolTipShowLength(10.0);
25 m_gui.setHoverInterval(0.75);
26 m_gui.setMaxToolTipWidth(400);
27
28 }
What the Gui does with this Input is: It is the backend implementation's responsibility to convert whatever input it receives into agui::MouseInput and agui::KeyboardInput. Now, in a case of A4 or SDL 1.2, the Input::poll() method would be implemented. In an event driven style such as A5, I created a processInput(ALLEGRO_EVENT& evt). That is called like this: 1 void Scene::processGuiInputEvent( ALLEGRO_EVENT* evt )
2 {
3 m_a5GuiInput.processEvent(*evt);
4 }
5
6...
7In Scene Manager...
8//main loop
9 while(m_gameIsRunning)
10 {
11
12 handled = false;
13 al_wait_for_event(queue,&evt);
14
15 bool hasNext = al_peek_next_event(queue,&next);
16 if(hasNext && next.type == ALLEGRO_EVENT_TIMER)
17 {
18 al_drop_next_event(queue);
19 }
20 //render the scene
21 if(m_needsRedraw && al_is_event_queue_empty(queue))
22 {
23 m_currentScene->render();
24 m_needsRedraw = false;
25 }
26
27 defaultBeginEventHandler(&evt);
28 m_currentScene->processEvent(&evt,handled);
29
30...
31 void SceneManager::defaultBeginEventHandler( ALLEGRO_EVENT*evt )
32 {
33
34 m_currentScene->processGuiInputEvent(evt);
35
36 if(evt->type == ALLEGRO_EVENT_TIMER && evt->timer.source == m_gameTimer)
37 {
38 m_needsRedraw = true;
39 m_currentScene->processGuiLogic();
40 m_devices->getNetClient()->tick();
41 }
42 else if(evt->type == ALLEGRO_EVENT_DISPLAY_RESIZE)
43 {
44 sendResizeMessage(evt->display.width,evt->display.height);
45 }
46 }
That is the basic idea... create an abstract set of functionality that any backend should be able to support, then implement it as a subclass and use polymorphism (and casting) to do the backend specific action. As for Layouts, I probably should have made every Widget own a layout, but instead I made it so that a Layout has complete control over the Widgets it is laying out. I prefer the idea of every Widget having a layout, and preferably a NULL layout can be supported. As to what you should work on with it... I guess games or level editors... I like your GUI, I think it looks quite nice. The default skin doesn't matter anyways :p Take Agui for example, it looks much nicer in action! {"name":"607025","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/5\/c5f02ac525f2c373d6fa7ae914a70bf9.png","w":476,"h":281,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/5\/c5f02ac525f2c373d6fa7ae914a70bf9"} Agui GUI API -> https://github.com/jmasterx/Agui |
axilmar
Member #1,204
April 2001
|
@Edgar: I do not like the artistic style of your GUI. It's primitive. Regarding the API, another way to handle events is to attach event handlers to interactive objects, like Flash does. You can read the Actionscript 3 documentation online, in Adobe's site. |
Thomas Fjellstrom
Member #476
June 2000
![]() |
axilmar said: Regarding the API, another way to handle events is to attach event handlers to interactive objects ie: listeners? -- |
axilmar
Member #1,204
April 2001
|
Yes, listeners. In Flash, every interactive object has the methods addEventListener and removeEventListener. My favorite thing though is signals and slots. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
axilmar said: @Edgar:I do not like the artistic style of your GUI. It's primitive. It's just a default style. You can style it any way you want, or at least you will be able to. I'm going to shuffle things around a bit now and let the user create the gui components themselves, like scroll bar buttons and scrollers. So you can make it look just like OSX if you want to. I'm not going to try and create system themes, but I should have a mechanism for loading guis from script files so the user could write their own system themes. @Everyone What is your favorite way to design a gui? Would you like a widget placement editor? Ie.. a gui editor? Would writing handlers for extra large video bitmaps that the gpu can't handle be useful to anyone? Do you want support for large video bitmaps? (Made up of several smaller video bitmaps and pieced together like a jigsaw) @Jmasterx For my input I decided to follow A5 and use a EagleEventHandler base class along with base classes for system, graphics context, timers, and input. Every backend has to implement these to function. jmasterx said: In an event driven style such as A5, I created a processInput(ALLEGRO_EVENT& evt). That is called like this: void Scene::processGuiInputEvent( ALLEGRO_EVENT* evt ) { m_a5GuiInput.processEvent(*evt); }
Doesn't this make your library depend on A5? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
axilmar
Member #1,204
April 2001
|
Edgar Reynaldo said: What is your favorite way to design a gui? Code. I've never seen a GUI being totally 100% designable by an editor. |
jmasterx
Member #11,410
October 2009
|
Edgar Reynaldo said: Doesn't this make your library depend on A5? No, because processEvent(ALLEGRO_EVENT* ...) is a method that is specific to Allero5Input class. The GUI is only aware of the Input class. If you used Agui with SDL you might have an SDLInput which might have processEvent(SDL_EVENT*...) agui::Allegro5Input::processEvent(...) calls Input::queueMouseEvent and queueKeyboardEvent. So there is no dependency on Allegro5. These are generically dequeued in Gui::logic(); In my example, my game uses Allegro5 to power it so I find it acceptable to make Allegro5 calls in it. But Agui itself can be compiled without any exteral libraries, check out the cmake file. The DECL_SPEC allow the library to be compiled as static or as a DLL; MSVC requires each class to be exported using _declspec when building as a DLL. I have 1 for core and 1 for backend to avoid conflicts in certain compilation situations. But because of how MSVCRT and such work, I don't recommend anyone use agui as a DLL unless you're using the exact same runtime. But it does work. Agui has nine patch support if you want to look into that. It is incredibly useful if you're going to support layouts. Agui GUI API -> https://github.com/jmasterx/Agui |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Well, I decided to just make a thin wrapper over EagleEvent's. The events and the keycodes and everything mesh with allegro - ALLEGRO_EVENT_KEY_UP is now EAGLE_EVENT_KEY_UP and so on.... So I guess it will just be a superset of all the library backends it supports. Here is the sourceforge project page I setup : And the svn repo : Please take a look at what I have so far, and tell me what you think of it! My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
jmasterx
Member #11,410
October 2009
|
The way you do it is how I did it too. I also mapped the gui to Allegro5 I looked over the code you committed and it looks fine. I didn't find Widgets but I guess you'll add those soon. Agui GUI API -> https://github.com/jmasterx/Agui |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Yeah, I haven't ported any widgets yet, first I have to finish the backend for A5 and then I can rebuild my gui on top of it. I shouldn't have to change a lot to port my widgets, but I will have to change all the drawing routines, and their input checks will change to use events. So, a little modification is necessary. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|