I LÖVE callbacks

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: I LÖVE callbacks

Post by airstruck »

kikito wrote:I have said everything I wanted to say and I don't wish to continue discussing this.
I didn't expect you to continue discussing it. Then you'd either have to maintain your position that library code never needs direct access to user input (that ship's going to sink pretty fast), or concede that sometimes it is reasonable for library code to have direct access to user input (and who wants to change their position, right?).
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: I LÖVE callbacks

Post by kikito »

Sure. Whatever makes you happy.
When I write def I mean function.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: I LÖVE callbacks

Post by airstruck »

I guess you're not convinced. I'll just leave this here, then.

It has drunkenness, and screen shake, and scaling, and a UI overlay that propagates events down to the game, but only when appropriate. Notice that no events are explicitly forwarded to the UI library by the game, and everything works. I challenge anyone to swap out this UI library with any other library and then tell me with a straight face that they think the resulting explosion of event-wiring-boilerplate is in any way necessary or preferable to simply calling ui:show() in gamestate:enter() and ui:hide() in gamestate:leave().
Attachments
beer.love
(867.18 KiB) Downloaded 101 times
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: I LÖVE callbacks

Post by zorg »

airstruck wrote:I challenge anyone to swap out this UI library with any other library and then tell me with a straight face that they think the resulting explosion of event-wiring-boilerplate is in any way necessary or preferable to simply calling ui:show() in gamestate:enter() and ui:hide() in gamestate:leave().
Granted you give me until the end of the weekend, i'll try :3
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: I LÖVE callbacks

Post by airstruck »

zorg wrote:Granted you give me until the end of the weekend, i'll try :3
I hope you get a chance to do it! I put an updated copy of that little example here if you want to look at that instead. It's basically the same, just commented and organized a little better, and disabled tab navigation on one of the UIs.
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: I LÖVE callbacks

Post by Positive07 »

I dont think simplicity is everything we should care about, having two functions call that do everything for the user doesnt make your API nice, as I understand your library is something like "Hey you are stupid and you can't write your UI code yourself so let me handle everything, just tell me how you want it to look".

To me a good API is one that let's you customize and hack even down to the minimal detail without having to rewrite the whole damn think or writing code for every little edge case. Of course perfection is impossible and an API like this may end up hiding some stuff, and it may also make coding a little harder in the sense that you have to wire up more stuff, but as Kikito said, you can have functions that do the wiring, but they don't have to be mandatory, just another utility the library provides.

So yes let me wire my input, if I want the library to not respond to mouse presses in a certain area let me do so, if I want to leave the textinput when the user presses "H" let me do so, if I want to remap each key of my keyboard for a certain textinput let me do so, if I want that moving the scroll wheel up moves the scrollbar down and moving it down actually scorlls up let me do so...

In this case I share Kikito's view point, a library that tries to do too much is a bad idea. You can't split things easily, customizing becomes hard, you have interdependencies everywhere.

I think all UI libraries out there lack this, input is too tied up to the UI when they are all different things.

EDIT: I must also add that there is no reason why Kikito nor I have to share your point of view airstruck nor you should share ours, I may also have differences with Kikito but who cares. Just make your UI library the best you can, if people like it they will use it, if they don't they will find alternatives or write their own, maybe you will inspire them. Feel free to code however you like, no one will criticize your work
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: I LÖVE callbacks

Post by airstruck »

as I understand your library is something like "Hey you are stupid and you can't write your UI code yourself so let me handle everything, just tell me how you want it to look".
I intended it more as "hey you're smart enough to use a library that handles the low level details for you so you can get down to the business of creating your UI without a bunch of fussing around."

It's interesting how this got turned around from me suggesting that users were smart enough to cope with a more rich event listener API into me apparently suggesting that users are stupid by working on a library that hides time-consuming implementation details behind a convenient high-level abstraction, in the interest of boosting productivity.
if I want the library to not respond to mouse presses in a certain area let me do so
You can. There's a sensible default behavior, but you can override it.
if I want to leave the textinput when the user presses "H" let me do so
You can. There's a sensible default behavior, but you can override it.
I want to remap each key of my keyboard for a certain textinput let me do so
You can if you feel strongly enough about it to expose all those functions instead of just complaining about built-in functionality. There's a ticket open that mentions this. I'm not going bother with it any time soon, because the default functionality suits me fine, but feel free to make a pull request. It wouldn't take much effort.
if I want that moving the scroll wheel up moves the scrollbar down and moving it down actually scorlls up let me do so...
You can. There's a sensible default behavior, but you can override it.
I think all UI libraries out there lack this, input is too tied up to the UI when they are all different things.
Of course UI libraries are concerned with user input. Receiving user input is probably the most important thing a UI does. Providing some level of abstraction for dealing with user input is a natural thing for a UI library to do.

In this case, an abstraction was necessary because the library works with multiple backends that expose user input in different ways. I wanted to be able to use the library on top of either Love or SDL without having to write implementation-specific input handling code.
no one will criticize your work
Criticize all you want, but complaining about the inclusion of default functionality that's easily overridden isn't going to convince me not to provide that functionality.
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: I LÖVE callbacks

Post by Positive07 »

airstruck wrote: I intended it more as "hey you're smart enough to use a library that handles the low level details for you so you can get down to the business of creating your UI without a bunch of fussing around."

It's interesting how this got turned around from me suggesting that users were smart enough to cope with a more rich event listener API into me apparently suggesting that users are stupid by working on a library that hides time-consuming implementation details behind a convenient high-level abstraction, in the interest of boosting productivity.
The problem is that when a library does something in a too specific way the users end up being discouraged because changing that behaviour is too difficult, so they end up throwing it away and even implementing their own, it's more of a psicological problem.

Most people start a project and when they don't find their perfect tools start to do Yak Shaving to fix the problem, Kikito wrote a great post about it too.

You as the owner of the library may not be able to see this, since it does exactly what you need it to do, and you know the internals so if it didn't do what you wanted you would easily fix it; well your solution may not be perfect for everyone, resulting in people getting frustrated when they can't do what they need.

Providing low level stuff is a great way to help fix this, you let the user easily change how everything works, of course you can provide sensible defaults as a high level feature, just let the users get to the low level stuff as easy as to the high level.
airstruck wrote: You can if you feel strongly enough about it to expose all those functions instead of just complaining about built-in functionality. There's a ticket open that mentions this. I'm not going bother with it any time soon, because the default functionality suits me fine, but feel free to make a pull request. It wouldn't take much effort.
Currently I don't have a project where I would like to use your library, if I ever have one and I happen to need that feature I'm gonna help you
airstruck wrote: Of course UI libraries are concerned with user input. Receiving user input is probably the most important thing a UI does. Providing some level of abstraction for dealing with user input is a natural thing for a UI library to do.
Well handling the input is what they do, so the abstraction would be "Okay, what's the input you have? I'll handle that for you" instead of "I'm gonna take this input and do this stuff, hope you don't bother"

I'm glad your library can override the default behaviours, that is a pretty nice thing. Can I simply, unhook the default behaviour entirely? If you can then your library does pretty much what Kikito and I are asking for, offers defaults, doesn't force you to use them, provides a way for defaults to not be used at all.
airstruck wrote: In this case, an abstraction was necessary because the library works with multiple backends that expose user input in different ways. I wanted to be able to use the library on top of either Love or SDL without having to write implementation-specific input handling code.
Well yes, your library is pretty cool on handling different backends.

The user could have done that if you provided a nice API too, again I don't complain but you should know that even though no one has tried before you, writing a UI library which is framework agnostic and uses backends to wire up to them should be totally possible. Just provide a nice API and you can wire up any backend you would like, this is of course pretty much harder if the UI library already wires itself up to the input, you can only use the library in the backends it targets.
airstruck wrote: Criticize all you want, but complaining about the inclusion of default functionality that's easily overridden isn't going to convince me not to provide that functionality.
Fine with me I'm not trying to convince you, not saying my way is better, just pointing out there are different points of view so you should respect them all even if you don't think like them. Kikito also tried to say this and I think that is the reason he didn't follow the discussion, because there isn't a definite conclusion, your point of view won't change, neither his or mine, no matter how much we discuss
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: I LÖVE callbacks

Post by airstruck »

Positive07 wrote:Providing low level stuff is a great way to help fix this, you let the user easily change how everything works, of course you can provide sensible defaults as a high level feature, just let the users get to the low level stuff as easy as to the high level.
The low level stuff is in there, of course, or the high level stuff on top of it wouldn't work. Whether everything everyone could ever want to use is exposed, I don't know. I figure if someone using the project needs some specific low level thing exposed that isn't already, they can open a ticket.
Can I simply, unhook the default behaviour entirely?
Many of the default behaviors can be "destroyed." If someone has an actual need to remove a specific behavior that can't be removed right now, they can open a ticket.
writing a UI library which is framework agnostic and uses backends to wire up to them should be totally possible.
I think it's easier said than done. Loading and displaying an image, loading a font and displaying text, even just drawing a rectangle is completely different in SDL and Love. All of that stuff already needed to be abstracted behind a common API, so that the library can say "draw a rectangle" and it works on any supported backend. In the same way, when you call layout:show(), a bunch of events are wired up, but how that actually happens depends on the backend.

Here's the actual event wiring code in question.

https://github.com/airstruck/luigi/blob ... e.lua#L119

I really don't think you want to write all of this every time you show a layout or raise it above the other layouts. Yes, events need to be wired up to each layout separately, unwired when when a layout is hidden, and they need to be unwired and rewired when a layout is raised to the top so that event handlers for things like drawing the UI and capturing mouse input fire in the right order. What you might want is your own specialized backend that only replaces this function in order to change, say, mouse coordinates before passing them along to the library. If this doesn't work for someone's actual use scenario, they can let me know and we can come up with a solution. Again, if users have specific problems they're facing, they can open tickets.
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: I LÖVE callbacks

Post by Positive07 »

Well good API that are really agnostic help with all that, I think we don't differ that much on beliefs.

As I said I would write a backend library which for example has functions like rectangle, image, circle and whatnot, that library would be written for each framework, say LÖVE, Lua SDL2 and every other one you may want.

Then I would require this library into my UI code and simply use that. The same with the input, I would separate it into a different library which has functions like getMousePosition and so and then I can require this into the UI, that library also provides functions to write framework specific code into it, for example basic callbacks for keypressed and keyreleased events and such that you would in turn call from love.keypressed and love.keyreleased or any other callback the framework may provide, with this you could easily wire up your framework with the input library.

If your input and graphic library are stateless you could even make all controls behave differently by wiring different states generated by this library into your elements.

You could of course provide a function that wires all this up by default, a function or argument to stop the library for wiring everything itself and facilities to wire specific things your self for an element, a set of elements, or everything you would like.

This API has a low level side(you can entirely change your backend and wire up new backends), medium level side (you can change the behaviour of an specific element, specific input), and high level side (wires everything itself and leaves the user with something that works with sane defaults).

Again modularity is a MUST, you end up with a bunch of related libraries, you should be able to use them separately, I think this is possible, because the wiring is also exposed as part of the API, just that normally it is handled by the other libaries.

I don't know if my way is perfect but it could work just as well as yours, I think both can cover mostly everything but I don't think mine rises that much the need of new tickets every single time, just do it yourself, the library doesn't need to cover every edge case because you can use it's API to extend it.

This my point of view on how I would like to tackle the problem, again I think your library is pretty neat and also looks good with all the default values, I wouldn't like to modify it though but that is my own taste again

I'm glad we could discuss this, you have really expanded my mind on how I would like some stuff to be done and how it's done, and how to tackle design choices and such. Thanks

But as I said we don't differ that much, sane default, offer low level API to modify the behaviour entirely, even disconnect it entirely from the normal input methods and drawing operations... We would just make our API different and separate modules differently but that is no big deal. I hope your library becomes even better and that you may have learned some new sight on this. We shouldn't really continue discussing this, I don't think neither of us is wrong, it can be done either way and both will work the same, it wouldn't be easier or harder just different.
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests