|
This thread is locked; no one can reply to it. |
1
2
|
lgui: a new gui for Allegro 5 |
frank.n
Member #16,879
July 2018
|
So I've written a GUI using Allegro 5 (C++ 11/14). Features
Widgets implemented
Layouts implemented
Test program Appearance Screenshots: Documentation Get and build Since this is developed for another project, there currently is no proper library distribution, I just import the code into my project, sharing some of the platform stuff. The API is still subject to change. Build with CMake. I'm not much of an expert with that, but I've successfully built it with g++ and/or clang on Linux, macOS, and Windows. Code sample 1// Have a TextLabel display what is typed into a TextField.
2// Also use a layout to arrange them vertically into a container.
3class MyWidget : public lgui::Container {
4 private:
5 lgui::TextField input;
6 lgui::TextLabel output;
7 lgui::VBoxLayout layout;
8
9 public:
10 MyWidget() {
11 input.on_text_changed.connect(&TextField::set_text, output);
12 // or: input.on_text_changed.connect([this](const std::string& str) { output.set_text(str); });
13 layout.add_item(input);
14 layout.add_item(output);
15 set_layout(&layout);
16 }
17};
18// (there is no need to derive from lgui::Container here, just for organisation)
19
20///////////////////////////////////////////////////////////////////
21
22// Allegro 5 main-loop snippet
23
24// .. set default style..
25
26lgui::GUI gui;
27lgui::Graphics gfx;
28
29MyWidget my_widget;
30
31// The widget at the top needs a size:
32my_widget.set_size(my_widget.measure_max(0.5*display_width, 0.5*display_height));
33
34gui.push_top_widget(my_widget);
35
36lgui::ExternalEvent event;
37ALLEGRO_EVENT a5_event;
38
39while(!quit) {
40 al_wait_for_event(event_queue, &a5_event);
41
42 switch(a5_event.type) {
43 // ...
44 default:
45 if (lgui::convert_a5_event(a5_event, event))
46 gui.push_external_event(event);
47 break;
48 }
49
50 if(redraw && al_is_event_queue_empty(event_queue)) {
51 gui.draw_widgets(gfx);
52 al_flip_display();
53 redraw = false;
54 }
55}
56gui.pop_top_widget();
Todo
Comments, questions, feedback are appreciated. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Very interesting. I develop a GUI of my own, Eagle. The difference between our widget headers is quite sharp. https://github.com/frank256/lgui/blob/master/src/lgui/widget.h https://github.com/EdgarReynaldo/EagleGUI/blob/master/include/Eagle/Gui/WidgetBase.hpp And my current redesign of the same header : https://github.com/EdgarReynaldo/EagleGUI/blob/core/include/Eagle/Gui2/WidgetBase2.hpp I'm going for a much more minimalist design in my latest refactor. 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 |
frank.n
Member #16,879
July 2018
|
Ah, interesting. The first thing I see in your header are the sub-widgets / children. That's exactly one of the things I have kept out of the base class. The widget class has been very small at the beginning, but grown out of convenience. The number of methods far exceeds the number of data members, though, which I've been rather reluctant to add to. The methods could use better grouping; I've just moved things around a bit after breakfast. I've seen your other thread about GUI core design, but cannot reply to it. lgui's documentation main page contains some stuff about lgui's design if you are interested. The docs are an extra target: make doc. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
frank256 said: The widget class has been very small at the beginning, but grown out of convenience. The number of methods far exceeds the number of data members, though, which I've been rather reluctant to add to. The methods could use better grouping; I've just moved things around a bit after breakfast. That's just what I've been trying to avoid with my latest redesign. Method proliferation prevention. That's why I'm delegating duties to sub objects, and I have callbacks you can overload when changing or upon change to the object. We can discuss Eagle here, but I don't want to distract from your GUI, so a new separate thread might be called for if you have something you want to discuss. Threads lock after a week of inactivity here, two if you're lucky and you pick the right board. I'll clone and try to build your gui here soon. EDIT I had to make a new project from scratch and add everything to it, but I got it working. It's a good little demo, you've got quite a lot done, congrats. 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 |
GullRaDriel
Member #3,861
September 2003
|
I'm SO tired of these 'I made a new C++ GUI'. While you stick to C++ you forbid the vast majority of C users to use your library in their code. On the opposite, making it in C would allow everyone to use it. /EndOfPersonnalRant Whatever, congrats on making something on your own. "Code is like shit - it only smells if it is not yours" |
Edgar Reynaldo
Major Reynaldo
May 2007
|
GullRaDriel said: I'm SO tired of these 'I made a new C++ GUI'. While you stick to C++ you forbid the vast majority of C users to use your library in their code. I'm SO tired of these "Why didn't you make your GUI in C so I can use it?" answers. If you want a C interface, there's nothing stopping you from doing it. 1class Foo {
2public :
3 void DoBarf() {printf("BARF\n");}
4 virtual void DoBazzle(int baz) {printf("%d" , baz*baz);}
5};
6
7class FooFighter : public Foo {
8public :
9 virtual void DoBazzle(int baz) {printf("%d" , baz*baz*baz);}
10};
11
12extern "C" {
13
14void foo_do_barf(Foo* foo) {
15 foo->DoBarf();
16}
17void foo_do_bazzle0(Foo* foo , int baz) {
18 foo->DoBazzle(baz);
19}
20};
Gotcha there Gully. 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 |
GullRaDriel
Member #3,861
September 2003
|
This will not compile with gcc only. I said C, not a silly C++ to C wrapper :-^p EDIT: Hello here BTW ^^ "Code is like shit - it only smells if it is not yours" |
jmasterx
Member #11,410
October 2009
|
Neat Agui GUI API -> https://github.com/jmasterx/Agui |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Let's see, what's the tally now? TGUI - Trent Gamblin Who else have I forgotten? The obligatory "why haven't we all been working on the same GUI for the last 10 years?" question is open. 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 |
DanielH
Member #934
January 2001
|
Slimy said: The obligatory "why haven't we all been working on the same GUI for the last 10 years?" question is open. I started mine for a few reasons. The main one was learning experience. The one I built is xml based. It was educational to build the parser, translator, etc. The second was because I didn't like the syntax the other ones were using. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
I was (s)trolling through Online Users and I stumbled across this old gui thread of yours, which answers my question from above. https://www.allegro.cc/forums/thread/613874 Sorry for derailing your thread with gui talk. xD 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 |
frank.n
Member #16,879
July 2018
|
I did not want to roll my own at first, but after surveying the GUI-scape, I thought there simply were none that had all the features I needed, mainly: Loose coupling between widgets Arguments are forwarded; when using Drag and drop Layouts layout.add_item_lt(label2, 0.5, 0.0); // left: 50%, top: 0% layout.add_item(drop_down2, { {lgui::RelativeLayout::Constraint::AlignLeft, label2 }, {lgui::RelativeLayout::Constraint::Below, label2}}); // To fix it to 40% to 60% of the parent's width and 30% to 70% of the parent's // height with a margin of 10 px on all sides: layout.add_item_ltrb({ label2, { 10 } }, 0.4, 0.3, 0.6, 0.7); // The same with a margin of top, left, right, bottom: 10, 5, 20, 30: layout.add_item_ltrb({ label2, { 10, 5, 20, 30 } }, 0.4, 0.3, 0.6, 0.7); As you can see, RelativeLayout is also a kind of PercentLayout. Maybe that could go into its own layout class, too, without all the complex, really "relative" stuff. Memory management Separate style classes Coding style I've also learned a lot in the process. Edgar Reynaldo said: I tried building your project, but it doesn't know where to find allegro. I don't install libraries in my compiler directory, so it will never work. I tried cmaking a code blocks project, but it was unconfigurable. I had to make a new project from scratch and add everything to it, but I got it working. It's a good little demo, you've got quite a lot done, congrats.
Thank you! |
Edgar Reynaldo
Major Reynaldo
May 2007
|
frank.n said:
Loose coupling between widgets Java did it all wrong. A thousand different listener classes is just dumb. In my GUI, widgets emit events, as a WidgetMsg to a parent, as an EagleEventSource to an EagleEventListener, or as a derived class callback. I always felt signals and slots was intrusive and just plain bad design. So if a widget has children, its parents get the message and react accordingly, like if a scroll bar gets a message from one of its scroll button children, or from the scroller child. WidgetMessages also get queued to the top level gui, for later retrieval and processing. A generic event is also emitted, which any listener class (such as the EagleEventHandler, which is an event queue), can deal with. Beyond that, if you need to override something that happens to a widget such as an specific event like when text is entered or a mouse gets clicked, then you override the WidgetBase::PrivateHandleEvent function. You can intercept any and all events that the widget receives and totally change its behavior. frank.n said:
Drag and drop I never saw the need for drag and drop. And besides, in my GUI it could be easily implemented by making a top most widget that is invisible that monitors mouse clicks and the widgets underneath the mouse at the time, along with any dragging events and drop events. But none of my widgets support 'dropping' anything onto them, but they could do it easily with a virtual HandleDrop(WidgetBase* widget_dropped) function. frank.n.stein said:
Layouts I don't know about that. I find that my layouts are pretty simple. Whenever you want to change the area of a widget, you call its SetWidgetArea function, which checks with its layout owner to see if it is an acceptable space to place the widget and returns the layout specified position for the widget. Any time the widget area is changed, a virtual member callback is executed, allowing you to reform your contents based on the new area. Widgets don't get to decide their actual position and dimensions, it's all handled by the layout. I suppose though, that a FlowLayout (which I haven't implemented yet) would need something like a preferred size to function properly. All my other layouts work great though. I have a dumb layout, a pin layout, a relative layout, a grid layout (which also works for the menu layout), splitter layouts, and I've experimented with animated layouts as well, which is really easy with my animation class. No more 3 column CSS Hell, where you can't get a damn table layout to work right ever. Table layout will be implemented, with variable size rows and columns, along with empty cells and spanning cells. frank.n.beans said: lgui::RelativeLayout::Constraint::AlignLeft Really? You can't pick a shorter name than a 4 namespace deep constant? I just use enums, and they work fine. frank.n.limas said:
Memory management Manually managing memory is one of the single greatest sources of bugs in code today. Memory leaks, dangling pointers, oh my! It's very simple to make your gui use shared pointers that can work for objects on the heap or the stack. Take for instance my "Eagle/SharedMemory.hpp" file : https://github.com/EdgarReynaldo/EagleGUI/blob/core/include/Eagle/SharedMemory.hpp It wraps a shared pointer and custom deleter so that stack and heap objects can be used together in a single object. Later on I have things like typedef SHAREDOBJECT<WidgetBase> SHAREDWIDGET; Which makes it an easily usable, easily copyable object that is safe to use for both stack and heap objects. No more worrying about memory. Less bugs FTW. frank.n said:
Separate style classes It's really not that much trouble to subclass a widget and override a single draw function or maybe two in case you need to handle events differently. I think external style classes are extranneous but I would need to look at your code to see what you're really doing. Mind pointing out a good example or where to look for the style code? frank.n said:
Coding style Ugh. I hate stretching my pinky_up_to_the_dang_underscore_key_all_the_time. It introduces typos. I follow a different convention. Named constants are uppercase generally if exposed. Classes and methods are CamelCase. Member variables are lower case, avoiding underscores if possible. No damn m_pHungarian junk I can't stand that it's not necessary and just makes code ugly and hard to type. frank.n said: I suppose there is an easy way to pass a library dir to cmake. You need to create a cmake variable in your CMakeLists.txt and set it to some default directory to search for allegro. Then I can specify the directory in cmake-gui and then reconfigure the project to look for allegro there. EDIT GWEN looked so promising from here : https://www.allegro.cc/forums/thread/608563/933616#target 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 |
Peter Hull
Member #1,136
March 2001
|
Edgar, [edit]: actually the github page is cited in the gamedev.net link you gave, so that wasn't news. Sorry.
|
Polybios
Member #12,293
October 2010
|
Whoa, Edgar, man, he now sees he must have done it all wrong. There are obviously different opinions about how to design a GUI... |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Polybios said: Whoa, Edgar, man, he now sees he must have done it all wrong. Hey hey hey. I wasn't trying to say he did it wrong, merely explaining my design choices as a logical follow up to his. If it works for him, good enough. I just wanted to show that it wasn't necessarily the only good way to do 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 |
frank.n
Member #16,879
July 2018
|
Edgar Reynaldo said: I always felt signals and slots was intrusive and just plain bad design. How can it be intrusive that the callee does not even have to know about the caller? I can hardly think of anything less intrusive than the way lgui does signals and slots. You can just register any function to be called by a signal, it does not even have to know about the fact it is called by a signal, you do not have to use signals yourself - it is actually not intrusive at all. Quote: It's really not that much trouble to subclass a widget and override a single draw function You can do that even when you have styles. The idea behind styles is that you want to change the look completely rather than have to override every draw function. Usually, you want some consistency in the appearance. Plus, it keeps the inheritance hierarchy clean. Quote: Really? You can't pick a shorter name than a 4 namespace deep constant? It is an enum, you can import it with using if need be, it is actually imported there, too, I think. Quote: Manually managing memory is one of the single greatest sources of bugs in code today. True. Well, I certainly do not mean to use new / delete manually all the time. I usually keep my widgets as member variables of classes that are ultimately created on the stack or in some container of an object residing on the stack. There are actually no "owning" pointers and almost no new / delete calls anywhere in my code, I think (I'd rather use make_unique). So no problems with that, plus I don't force anyone to use shared pointers: not intrusive. I think there is middle ground between using C style pointers plus manual new/delete calls and using the bulldozer of wrapping everything in shared pointers. I don't like having no control plus I think it leads to bad code because you do not have to think about ownership anymore. Quote: It's very simple to make your gui use shared pointers that can work for objects on the heap or the stack. Shared pointers to objects on the stack? I don't think that is a good idea. Quote: frank.n.stein said Now I doubt you were even serious. Drunk? I took a look at GWEN, too (and an active fork called GWORK, I think), but found the code to be pretty unreadable. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
frank.n said:
Edgar Reynaldo said: I always felt signals and slots was intrusive and just plain bad design. How can it be intrusive that the callee does not even have to know about the caller? I can hardly think of anything less intrusive than the way lgui does signals and slots. You can just register any function to be called by a signal, it does not even have to know about the fact it is called by a signal, you do not have to use signals yourself - it is actually not intrusive at all. How did you solve the method signature typing problem? virtual base class with operator()? When being called, how does the callback know who called it? The source of the call often has information vital to the functioning of the callback. How do you solve scoping? How do you solve forwarding? What about return values? Heard of boost? It's a template nightmare to try and deal with these kinds of issues. I'd like to see some sample code of yours that deals with binding values and functions to signals and slots. I don't have any of these problems with my event system and widget messaging. In my gui you can listen to any widget and get every event it ever emits at the time it is emitted. You can query the gui for messages, use an event queue, or listen to the widget directly. With signals and slots, you have to have a slot for every message you want to receive. This means you need to add a signal to every slot if you want all the messages. Multiply that by 50 widgets and it's a nightmare. With an event and listener system you can listen to every event you want at once or one at a time with very little overhead. With signals and slots you have to worry about threading issues, where with an event queue it's already thread safe. To me, it's not worth all the hassle. frank.n said:
Edgar Reynaldo said: It's really not that much trouble to subclass a widget and override a single draw function You can do that even when you have styles. The idea behind styles is that you want to change the look completely rather than have to override every draw function. Usually, you want some consistency in the appearance. Plus, it keeps the inheritance hierarchy clean. Like I said, kindly point out where to look for your styling code. I would like to see how you implemented it. frank.n said: True. Well, I certainly do not mean to use new / delete manually all the time. I usually keep my widgets as member variables of classes that are ultimately created on the stack or in some container of an object residing on the stack. There are actually no "owning" pointers and almost no new / delete calls anywhere in my code, I think (I'd rather use make_unique). So no problems with that, plus I don't force anyone to use shared pointers: not intrusive. I think there is middle ground between using C style pointers plus manual new/delete calls and using the bulldozer of wrapping everything in shared pointers. I don't like having no control plus I think it leads to bad code because you do not have to think about ownership anymore. Edgar Reynaldo said: It's very simple to make your gui use shared pointers that can work for objects on the heap or the stack. Shared pointers to objects on the stack? I don't think that is a good idea. I came to this place because manually managing memory was a tiresome buggy chore. Forcing your users to put everything on the stack or manage the memory themself sucks. I finally decided I was sick of trying to decide who was responsible for managing the memory. At one point I even had layouts managing memory and that was a terrible idea which I canned and traded in for shared pointers. frank.n.furter said:
Edgar Reynaldo said: frank.n.stein Now I doubt you were even serious. Drunk? I was just joking around. I couldn't resist. Your name was just too convenient. 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 |
frank.n
Member #16,879
July 2018
|
How old are you? Edit: Never mind. Cheers, everyone. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Learn how to take a joke. If you can't provide a simple code example of how to use your signals and slots, I'm not going to bother reading your source or docs, especially when they don't build with the build system you provided. As for shared objects on the stack they work just like any other object on the stack. If you give out a pointer that lives beyond their scope it's a dangling pointer. No safer or more dangerous than a regular object. This way there is a common interface. If I automatically 'owned' new widgets passed into a gui or layout, then they better be on the heap, but you can't guarantee that. So I made it so that to create a SHAREDOBJECT, you need to call a template function called HeapObject or StackObject, and pass it a pointer. It is now explicit and clear whether or not the object should be destroyed when its last reference goes out of scope. As to who's being a grownup, you're the one refusing to answer questions. I've asked several times if you could point out your styling code or if you would give an example of your signals and slots. 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 |
frank.n
Member #16,879
July 2018
|
Never mind. I thought you were trolling. In fact, I have provided several examples of how to use the signals in this thread already: lgui::TextField input; lgui::TextLabel output; input.on_text_changed.connect([&output](const std::string& str) { output.set_text(str); }); Here, the label will mirror the text of the text field through connecting the TextField::set_text to the signal. In fact, the signal will call the provided lambda which could do whatever it pleases. I usually have this as part of a class inheriting from lgui::BasicContainer or lgui::Container and capture this which automagically gives me access to every member variable. There is also a convenience-overload of the connect-method which is passed a pointer-to-member-function and a reference to an object instance. So an alternative formulation would be this: lgui::TextField input; lgui::TextLabel output; input.on_text_changed.connect(&TextField::set_text, output); The slots are just std::function (anything callable). The signals are usually public members prefixed with on_ and use the signal template. Declaring a signal looks like this: lgui::Signal <const std::string&> on_text_changed; The template parameters represent the signature of the functionals that can be connected. You can always connect functionals taking less parameters, but no functionals taking more parameters. To emit a signal, the widget just calls on_text_changed.emit(text); If you need the source of the call, you could use separate lambdas per source to also forward the source (or use std::bind). It would also be easy to extend the signal template to always forward a source reference. I had thought about doing that, but came to the impression that keeping it a one-way street (=simpler) would be better. Well, it's probably just not there because I haven't needed it so far. Signal header can be found here: It basically uses variadic templates and perfect forwarding. Most of the complexity comes from handling connecting and disconnecting to a signal even while the signal is being emitted. I've never actually used the stuff to disconnect individually, so maybe it will have to go in the future. I know boost and I really don't like it. Styles can be found here: |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Actually, I think I've decided to put the kabosh on the shared pointer business. They really don't make sense semantically. Because now no one owns the memory, everybody does. And it messes with the destruction order. I thought they were such a good idea at first and I always get advised to use shared pointers now in the modern day and age. Instead, I decided to give widgets a single owner, the gui factory. And The system would own all instances of gui factories, and so the system is responsible for destroying widgets on close. Likewise, an Image owns all of its sub images, and a window owns all of its images. The user is still free to allocate anything on the stack, or use new and delete, or use the interface provided for widget / image / window creation. Ultimately the system will own everything. You can free anything upon request though, to save memory. Regarding signals / slots, am I right in thinking that each widget has its own predefined signature type for each event it might emit? If so, the user has to rely on documentation to get the type right, and if it varies for every widget and every event, then it seems to be over complicating things. I've never seen so many abstract virtual functions before... That's a very complex interface for styles. frank.n said:
lgui::TextField input; lgui::TextLabel output; input.on_text_changed.connect([&output](const std::string& str) { output.set_text(str); });
Okay, now this I like. I'm still not very good with lambda functions. Are you capturing a reference to the TextLabel 'output'? How does that work to bind the output object? 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
|
It looks like an anonymous function that captures a reference to the output widget. However,if output is allocated on the stack and it disappears then the reference points to garbage and things crash. You could also capture output by value but in this situation that is not too helpful. Agui GUI API -> https://github.com/jmasterx/Agui |
Edgar Reynaldo
Major Reynaldo
May 2007
|
I could just never wrap my head around things like std::bind and std::mem_func and the like. So frank.n, does each widget get its own set of signals? With different types? I like the immediacy of signals, but they are very complex.. 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 |
frank.n
Member #16,879
July 2018
|
Edgar Reynaldo said: So frank.n, does each widget get its own set of signals? With different types? Yeah, they are declared individually per widget, the widget base class has none. Currently, it's usually just one per widget with one distinct signature each, mostly emitting one value only. They are intended for the semantically interesting stuff that is specific for the widget. jmasterx said: However,if output is allocated on the stack and it disappears then the reference points to garbage and things crash. Right. That's the price to pay for the loose coupling. Mostly, widgets connected with each other are like siblings, ownership-wise, so they usually end up as members of the same class in my use cases. This makes the problem mostly a no-issue for me (I actually thought it was more problematic). Another downside of the current approach is that signals cannot be overloaded (except that you can always choose to ignore parameters, i.e. you can always connect a functional taking no arguments even if the signal emitted many of them). Edgar Reynaldo said: Because now no one owns the memory, everybody does. And it messes with the destruction order. Exactly. Quote: That's a very complex interface for styles. Yes. I'm not entirely satisfied with it, especially as every new widget added (to the lgui "core", that is) will introduce additional methods. Maybe I should have an abstract style class for each widget, with the style bundling them together and some generic method to get the appropriate style object instances. Or find some other useful abstraction over things to draw. But the original idea was to keep things simple, so I'll go with that existing solution for now. |
|
1
2
|