-
-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Signals #112
Signals #112
Conversation
I don't fully understand how this would be used, how do you e.g. connect the "pressed" event of a certain button? Based on what I can see in the code, you would have to check if signalName matches e.g. "BtnName" inside MySignalManager::connect and then call There will have to be some kind of SignalManager class in the final implementation in order to load signals from widget files, but unless I'm missing something I'm not convinced that this implementation really makes things better than they currently are. |
Well i wrote this part of code for my own use.
Doing it like that, i don't need iterate through all widgets to connect them. Although now when i write this, it could be better idea to simply iterate through all widgets. |
I think it would be much more useful if it had an API like I haven't previously though about connecting callbacks on widgets that don't exist yet. That is indeed a benefit of having a SignalManager class. When properly implemented, the I don't know how the API should look like though, |
It is a good idea, but what if "BtnName" is not button, but slider and he hasn't "pressed" signal at all. I used my class by declaring in my program what values are available, and by widget type and "connect value" connected widgets to these values. And even auto loading form by signal of panel resizing.
Connected this panel to resize signal and loaded form with the biggest size that could be located inside. In what you suggest it is impossible, because program need to know names of widget before, even connecting to signal. Also in API like SignalManager::connect("BtnName", "pressed", []{}). are some problems like:
|
You wouldn't have to search any gui objects, when a widget is added to its parent the global signal manager is accessed directly.
I can imagine that it could be useful sometimes to use the same callback function for different widgets. However, what I had in mind was similar to creating a unique function for each event. For example, the pressed event of the button would have "BtnName_Pressed" as ID and you would need to call
Maybe I'll add something like this in the future, but the get function supports recursive search, so if your name is unique then you can already just do
This could also be said about using the get function or using the connect function with a wrong parameter. Any solution will actually have this problem. In your code you just moved this into the user code. Your SignalManager::connect function also only takes a string id and a Widget as parameter which means it is up to the user to make sure the widget is of the right type.
This is true. I haven't chosen any design yet, when I talk about "my design" I'm just referring to the rough design that I though about so far but never worked out in detail. I do however expect the final implementation to be something similar to what I have thought about, i.e. something simple. You are correct that with my design it is impossible to do what you want. If you could come up with a design that is still simple (and thus closer to what I had in mind) while still having the ability to be extended (by those who choose to) then I definitely would consider it for inclusion in TGUI. |
That's only if widget was loaded after signal, but what if situation was reversed and signal was added after the widget to enable some situation. Gui isn't unique therefore in which gui should we search, or should it be marked that it don't work in that way. I will write it in the way that you spoke about, |
You could store a map of widgets names to
I think it is a good idea to add this. Btw, the member should probably be called "UserData" in the textform instead of "user_data", to conform with the others properties. In the code I also noticed you were using lower_case names for variables instead of camelCase like is being used in the rest of the code.
Could you elaborate on this? I didn't really understand what you mean. |
Form => file loaded by loadWidgetsFromFile I mean to add some way to load another form by panel from form. In example. PS. I now funded the userdata member in widget. If it should be saved to form the what should I do. Another function to get/set (only form string "userdata") or save only if convertible to sf::String or std::string |
I'm not sure if what you describe should really be handled by the library. The loadWidgetsFromFile exists to load widgets at one moment in time. Even if it would contain the necessary logic to load right200x200.txt, the code isn't executed again when you resize your windows so it won't magically replace your widgets with something from another file. Loading different widgets when resizing will always have to be implemented on a higher level, the loadWidgetsFromFile will just load widgets how they are described in the file and panels won't store that they were loaded from such a file. What does seem like a good idea is referencing other files. You would create a panel in one form and the contents of that panel would be stored in a different form. But that relationship would be static, if the first form contains a reference to "right.txt", then it will request to load a file called "right.txt" and nothing else. You could do this via a user defined function (which would do the actual loading so that you could e.g. load the file from a different path or from a zip file). That would still allow you to load "right200x200.txt" at that moment but the widgets won't be changed afterwards. Maybe you should just load all panels? You would have a group loaded from "right100x100.txt" and another one loaded from "right200x200.txt" and when resizing the window you just hide one and show the other?
I would be fine if it only worked for |
I mean we have onSizeChange event? We could internally connect thus signal in panel. As panel has form value then it could load form200x200.txt or bigger with size change event and replace it's content. With signaenager widgets would connect to event functions automatically. |
I don't fully understand the details of how you are going to do it all, but as long as the logic happens in your own code it is fine. |
New idea for signalManager but it isn't working because I don't understand how to connect and hold unconnected function in signalManager. |
Reimplemented implementation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I spend less time than expected on the other stuff that I was working on so I already found the time to review this today. I haven't actually tested the implementation yet, but it will probably be fine based on what I see in the test you included.
Thanks for the effort you have already put into this. I'll try to test it soon so that this can be merged once the minor changes are made.
/cmake-build-debug | ||
/cmake-build-release | ||
/.idea |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"cmake-build-debug" and "cmake-build-release" shouldn't be in .gitignore since they are specific to your build. The .idea can remain in .gitignore as this might benefit more people.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use clion ide and it copies files in this folders. GitHub is olweys chalking the folders if it could add then to commit and so on. Therefore in gitignore I ignored builds folder for clion for better stability and working. It shouldn't do any bad think to anyone through because I doubt tgui would use them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize that the ide created those debug and release folders too, I though you created those and the ide only created the .idea folder.
Since those folder names seem to be the default setting for clion, you can keep these folders in .gitignore too.
changelog.txt
Outdated
- Added UserData property to widgets | ||
- Changed method of storing names of widgets | ||
- Fixed adding the same widget to multiple containers | ||
- Added possibility to connect signals before creating widget |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to change the changelog, I will take care of it later. The "Added UserData property to widgets" isn't really accurate as it already existed for a while, it just couldn't be saved/loaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete this commit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the changes to this file should be removed.
include/TGUI/Container.hpp
Outdated
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
/// @brief Returns a list of the names of all the widgets in this container | ||
/// | ||
/// @return Vector of all widget names | ||
/// | ||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
const std::vector<sf::String>& getWidgetNames() const | ||
TGUI_DEPRECATED("Use for(getWidgets())->getWidgetName() instead") const std::vector<sf::String> getWidgetNames() const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for(getWidgets())->getWidgetName()
might not be very clear. Maybe something like Use getWidgets() and Widget::getWidgetName instead
as description?
include/TGUI/Gui.hpp
Outdated
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
/// @brief Returns a list of the names of all the widgets | ||
/// | ||
/// @return Vector of all widget names | ||
/// | ||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
const std::vector<sf::String>& getWidgetNames() const; | ||
|
||
TGUI_DEPRECATED("Use for(getWidgets())->getWidgetName() instead") const std::vector<sf::String> getWidgetNames() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as before, TGUI_DEPRECATED description could be more clear.
TGUI_API bool isWhitespace(char32_t character); | ||
TGUI_API bool isWhitespace(uint32_t character); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TGUI_NEXT code shouldn't really be touched. That code was added for myself as a reference where things should change in 0.9. Originally the code did compile, but I guess that by now you should probably never define it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I declared TGUI_NEXT and checked if it would copile if I deleted deprecated code. But it didn't because in my gcc char and char32 were the same and I have thus some problem with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TGUI_NEXT is an undocumented define that should actually never be used (and as you noticed doesn't even compile). I appreciate that you tried to check with different defines though.
It actually doesn't matter what the code says, it won't be compiled anyway. So you don't have to bother undoing your change, we can keep the "uint32_t" version.
include/TGUI/Widget.hpp
Outdated
@@ -428,7 +428,7 @@ namespace tgui | |||
/// | |||
/// Examples: | |||
/// @code | |||
/// widget->setUserData("Data"); | |||
/// widget->setUserData("Data"); ///Warning: const char* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The warning is a good idea. But maybe something slightly more verbose like // Note: type to retrieve with getUserData is 'const char*' here
?
include/TGUI/Widget.hpp
Outdated
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
/// @brief Returns the name of a widget | ||
/// | ||
/// @return Name of the widget or an empty string when the widget didn't exist or wasn't given a name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy-paste issue: the widget always exists if this function can be called. So it's only empty if it wasn't given a name
bool isWhitespace(char32_t character) | ||
bool isWhitespace(uint32_t character) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error as described before. On compile time.
tests/Sprite.cpp
Outdated
@@ -503,7 +503,7 @@ TEST_CASE("[Sprite]") | |||
|
|||
SECTION("getTexture has a version to change the texture and a const version") | |||
{ | |||
sprite.getTexture().setSmooth(false); | |||
//sprite.getTexture().setSmooth(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this commented for a reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TGUI_NEXT deleted procedure that could return non const value and build was impossible in deprecated code removal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing deprecated code isn't documented so its normal that you didn't know, but to remove deprecated code you should define TGUI_REMOVE_DEPRECATED_CODE
. The TGUI_NEXT
define had a different goal (and it is no longer relevant). Once I've merged your changes I'm going to remove the TGUI_NEXT stuff to avoid further confusion.
So this line should be uncommented.
I will change this and when path will be ready squash all commits. |
You can squash the commits. |
72caf05
to
8d6815d
Compare
Some errors when squashing. |
There were some errors. Name of widget was changing when added to container as add(widget, name) and tests wont pass. This should be changed to add(widget) in all widgets but there is to much dependency as add is virtual method. It should be changed in next major version. |
Fixed adding the same widget to multiple containers Added possibility to connect signals before creating widget Update .gitignore Now UserData property will be saved as string if possible
Why were there errors? The code before you squashed it worked fine, so what did you change? |
I think I know what you mean. I didn't notice that you were using it like that, but setWidgetName should be private and the user should never call it. In 0.9 we could indeed change the design so that the add function no longer takes the name as parameter and where the user should set a name via setWidgetName, but for 0.8 the code should continue to function like before. This means that in 0.8 the name should still only be set via the container.add method, you should only be moving the location where the name is stored. The setWidgetName can be private because Container is a friend class of Widget. The getter function should remain public. |
Well there was error in deleting signals because I didn't disconnected them in remove(Widget*) function. We could let name setting method be like it is but there should be disclaimer that adding it to container will reset it name and name should be added after Adding it or to change name when adding to contner. Adding virtual add(Widget) method is a option on its own. Or changing std::string to optional string then checking if string was settled and only then changing the name. add(widget, "name") -> setname |
This has been manually merged in ac2bc92 I've added a warning to setWidgetName that it will be overwritten on |
Simple Signal Manager implementation that enables you to write your own manager.
Now you can set connect value to the widget in textform.
Widget will be send to your manager with this value.
You can now connect your widget from textform to enable any usability that you desire.