Where is the mouse?
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
-
- Veteran
- Posts: 359
- Joined: Sat Feb 25, 2006 11:09 am
- Location: Sant Cugat del Vallès (Barcelona, Spain)
- Contact:
Where is the mouse?
The topic subject is quite literal: I would need to retrieve the position of the mouse cursor from certain points of my code. After searching the reference and these forums, and even trying to look through Ren'py's source, the only thing I've been able to find are the events for custom Displayables, but I don't feel that converting my UI functions into Displayables would be the appropriate solution, and I don't know if I could even do it at all.
To the specifics: on my "inventory" and "shopping" UIs, I would like to add a small popup window with information about an item when the user hovers the mouse over it. If you take a look at the attached code, you'll see that it already uses the hovered and unhovered arguments for the appropriate buttons and keeps track of the item to "popup", if any. The code to construct the popup itself will be almost trivial compared with the rest of the UI, so I only need to find out how to place it "hanging" from the cursor.
To the specifics: on my "inventory" and "shopping" UIs, I would like to add a small popup window with information about an item when the user hovers the mouse over it. If you take a look at the attached code, you'll see that it already uses the hovered and unhovered arguments for the appropriate buttons and keeps track of the item to "popup", if any. The code to construct the popup itself will be almost trivial compared with the rest of the UI, so I only need to find out how to place it "hanging" from the cursor.
- Attachments
-
- shop.rpy
- The code of the shopping UI; I hope it helps to clarify what I'm trying to do (specially lines 97-99).
- (7.79 KiB) Downloaded 164 times
I have failed to meet my deadlines so many times I'm not announcing my projects anymore. Whatever I'm working on, it'll be released when it is ready ![Razz :P](./images/smilies/icon_razz.gif)
![Razz :P](./images/smilies/icon_razz.gif)
- PyTom
- Ren'Py Creator
- Posts: 16097
- Joined: Mon Feb 02, 2004 10:58 am
- Completed: Moonlight Walks
- Projects: Ren'Py
- IRC Nick: renpytom
- Github: renpytom
- itch: renpytom
- Location: Kings Park, NY
- Contact:
Re: Where is the mouse?
Um... that information is not made available to user code. In fact, Ren'Py is capable of operating without a mouse, or without the mouse in the window.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom(When was the last time you backed up your game?)
Software > Drama • https://www.patreon.com/renpytom
-
- Veteran
- Posts: 359
- Joined: Sat Feb 25, 2006 11:09 am
- Location: Sant Cugat del Vallès (Barcelona, Spain)
- Contact:
Re: Where is the mouse?
![Crying or Very sad :cry:](./images/smilies/icon_cry.gif)
I think I've come up with an alternative approach... do all the UI widget functions return the widget they create, like ui.viewport() does? (I know viewport does only because an example uses it... there is no mention to return values in the reference for any of these functions). If so, is it possible to find out the actual position of those widget objects?
And, another issue I have realized by your answer... do the hovered and unhovered functions of an ui.button rely on actual mouse hovering of just care about gaining/losing focus, regardless of input method? I hope it's the later, although then the names are a bit missleading.
I have failed to meet my deadlines so many times I'm not announcing my projects anymore. Whatever I'm working on, it'll be released when it is ready ![Razz :P](./images/smilies/icon_razz.gif)
![Razz :P](./images/smilies/icon_razz.gif)
- PyTom
- Ren'Py Creator
- Posts: 16097
- Joined: Mon Feb 02, 2004 10:58 am
- Completed: Moonlight Walks
- Projects: Ren'Py
- IRC Nick: renpytom
- Github: renpytom
- itch: renpytom
- Location: Kings Park, NY
- Contact:
Re: Where is the mouse?
Most of the ui functions return the displayable they create. (The exceptions are things like ui.menu, which creates multiple displayables.)
hovered and unhovered are just poor names for focused and unfocused, from back in the days before I supported keyboard and joystick input.
hovered and unhovered are just poor names for focused and unfocused, from back in the days before I supported keyboard and joystick input.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom(When was the last time you backed up your game?)
Software > Drama • https://www.patreon.com/renpytom
-
- Veteran
- Posts: 359
- Joined: Sat Feb 25, 2006 11:09 am
- Location: Sant Cugat del Vallès (Barcelona, Spain)
- Contact:
Re: Where is the mouse?
That's the important question ^^;herenvardo wrote:If so, is it possible to find out the actual position of those widget objects?
I've checked the reference for no avail; so I've taken a look through the Ren'py source, finding out the classes that represent these widgets, following up the hierarchy looking for "interesting" fields, until reached Displayable... (between this, and my attempt to mess up with text tags two days ago, I think I'm getting used to sneak through these sources
![Laughing :lol:](./images/smilies/icon_lol.gif)
![Laughing :lol:](./images/smilies/icon_lol.gif)
what would myButton.get_placement() return?, where myButton would be a renpy.display.behavior.Button. Ok, I know it will return a tuple, and the name of these fields; but it'd be good to know their meanings (ie: are they absolute positions, relative to the container, or relative to something obscure that I haven't found yet?; what do the offset fields exactly mean?)
I have failed to meet my deadlines so many times I'm not announcing my projects anymore. Whatever I'm working on, it'll be released when it is ready ![Razz :P](./images/smilies/icon_razz.gif)
![Razz :P](./images/smilies/icon_razz.gif)
- PyTom
- Ren'Py Creator
- Posts: 16097
- Joined: Mon Feb 02, 2004 10:58 am
- Completed: Moonlight Walks
- Projects: Ren'Py
- IRC Nick: renpytom
- Github: renpytom
- itch: renpytom
- Location: Kings Park, NY
- Contact:
Re: Where is the mouse?
get_position returns the xpos, ypos, xanchor, yanchor, xoffset, yoffset tuple take from style properties. (Except for moves, in which case it returns a moving equivalent.)
There's no way to know from a displayable where it will wind up on the screen. All of the displayables it's inside get a shot at moving it, and so the actual positions aren't computed until right before things are drawn to the screen.
There's no way to know from a displayable where it will wind up on the screen. All of the displayables it's inside get a shot at moving it, and so the actual positions aren't computed until right before things are drawn to the screen.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom(When was the last time you backed up your game?)
Software > Drama • https://www.patreon.com/renpytom
-
- Veteran
- Posts: 359
- Joined: Sat Feb 25, 2006 11:09 am
- Location: Sant Cugat del Vallès (Barcelona, Spain)
- Contact:
Re: Where is the mouse?
Ouch! Plan B also failed, let's try with plan C... oops, first I need to come up with a plan C ^^;
*** after a while wandering through the references and ren'py's source again... ***
got it! If I know beforehand where the buttons will be, I won't need to find it out on runtime![Very Happy :D](./images/smilies/icon_biggrin.gif)
*** takes a screenshot of the UI "as is", and starts measuring pixel distances and that kind of stuff for a while...
finally comes up with a formula, translates it to python code, and tests it... ***
![Image](http://herenvardo.googlepages.com/shopshot.jpg)
yeah!!! It's working!! I've tested using also the keyboard and gamepad, and it's (mostly) going as intended... except for one thing
When the button loses focus, the popup stays there ![Crying or Very sad :cry:](./images/smilies/icon_cry.gif)
I've attached the full ui.rpy file (the relevant function, Shop(...), begins at line 105), but I'll summarize here the key parts of the code:
The function begins with some initializations and defines a few helper functions; specially this one:
Speciall emphasis on the "if itemH is not None:" line; it should be the one that "closes" the popup when appropriate.
The list of "item" buttons is produced within a loop, of which the most important statement would be:
Within this context, id is alwayes one of "Buy", "Buyback", or "Sell" (depending on the list of items that is being produced); and i is the index of the relevant item within the list.
The main work of the function is an endless loop that calls many ui.whatever widget functions, then:
The 'h' cases are working properly, so whenever the focus enters a new button, the popup moves acordingly and updates its contents. But when focus leaves the button (ie: moving the mouse to an empty area of the screen), the popup stays there, and it should disappear. So, what am I doing wrong?
*** after a while wandering through the references and ren'py's source again... ***
got it! If I know beforehand where the buttons will be, I won't need to find it out on runtime
![Very Happy :D](./images/smilies/icon_biggrin.gif)
*** takes a screenshot of the UI "as is", and starts measuring pixel distances and that kind of stuff for a while...
finally comes up with a formula, translates it to python code, and tests it... ***
![Image](http://herenvardo.googlepages.com/shopshot.jpg)
yeah!!! It's working!! I've tested using also the keyboard and gamepad, and it's (mostly) going as intended... except for one thing
![Confused :?](./images/smilies/icon_confused.gif)
![Crying or Very sad :cry:](./images/smilies/icon_cry.gif)
I've attached the full ui.rpy file (the relevant function, Shop(...), begins at line 105), but I'll summarize here the key parts of the code:
The function begins with some initializations and defines a few helper functions; specially this one:
Code: Select all
def itemPopup(margin=40):
if itemH is not None:
yp = 104 + 56*posH
if posH > 4:
ya = 1.0
else:
ya = 0.0
if sideH=="left":
xa, xp = 0.0, margin
else:
xa, xp = 1.0, config.screen_width-margin
text = itemH.popupdesc()
if priceH is not None:
text += "\n{b}Buy price{/b}: %s"%(money(priceH))
ui.frame(xpos=xp, xanchor=xa, ypos=yp, yanchor=ya, xmaximum=300, background=Solid("#40404080"))
ui.text(text, color="#fff")
The list of "item" buttons is produced within a loop, of which the most important statement would be:
Code: Select all
ui.textbutton(text, size=14, size_group=id,
clicked =ui.returns(("c"+id, i)),
hovered =ui.returns(("h"+id, i)),
unhovered=ui.returns(("u"+id, None))
The main work of the function is an endless loop that calls many ui.whatever widget functions, then:
Code: Select all
# The floating window:
itemPopup()
ret = ui.interact()
if isinstance(ret, tuple):
# there is some more code here handling other values of ret.
if ret[0] == "hBuy":
itemH = Stock[ret[1]][0]
sideH = "left"
posH = ret[1]-LListPos
priceH = Stock[ret[1]][1]
continue
if ret[0] == "hBuyback":
itemH = buyback[ret[1]][0]
sideH = "left"
posH = ret[1]-LListPos
priceH = None
continue
if ret[0] == "hSell":
itemH = inventory[ret[1]][0]
sideH = "right"
posH = ret[1]-RListPos
priceH = None
continue
if ret[0]=="uBuy":
itemH = None
continue
if ret[0]=="uBuyback":
itemH = None
continue
if ret[0]=="uSell":
itemH = None
continue
- Attachments
-
- ui.rpy
- The code for all of my UIs; the relevant part starts at line 105.
- (15.54 KiB) Downloaded 154 times
I have failed to meet my deadlines so many times I'm not announcing my projects anymore. Whatever I'm working on, it'll be released when it is ready ![Razz :P](./images/smilies/icon_razz.gif)
![Razz :P](./images/smilies/icon_razz.gif)
- PyTom
- Ren'Py Creator
- Posts: 16097
- Joined: Mon Feb 02, 2004 10:58 am
- Completed: Moonlight Walks
- Projects: Ren'Py
- IRC Nick: renpytom
- Github: renpytom
- itch: renpytom
- Location: Kings Park, NY
- Contact:
Re: Where is the mouse?
Hm... the unhovered callback can't return a value. (IIRC, there was some infinite loop that is easily caused if it can.)
You probably want to use ui.add and renpy.restart_interaction in the hover callback, and ui.remove and renpy.restart_interaction in the unhover callback.
You probably want to use ui.add and renpy.restart_interaction in the hover callback, and ui.remove and renpy.restart_interaction in the unhover callback.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom(When was the last time you backed up your game?)
Software > Drama • https://www.patreon.com/renpytom
-
- Veteran
- Posts: 359
- Joined: Sat Feb 25, 2006 11:09 am
- Location: Sant Cugat del Vallès (Barcelona, Spain)
- Contact:
Re: Where is the mouse?
Well, I'm getting the infinite loop anyway ^^; I changed the unhovered from ui.returns(...) to a new function I've named onUnhover. The first go at coding this function looked like this:PyTom wrote:Hm... the unhovered callback can't return a value. (IIRC, there was some infinite loop that is easily caused if it can.)
You probably want to use ui.add and renpy.restart_interaction in the hover callback, and ui.remove and renpy.restart_interaction in the unhover callback.
Code: Select all
def onUnhover():
global itemH # I've made it global to be able to do that
itemH = None
renpy.restart_interaction()
![Crying or Very sad :cry:](./images/smilies/icon_cry.gif)
So, after plan C blatantly failing, and being to lazy to come up with a plan D, I went for plan C-bis: I took out the renpy.restart_interaction call from onUnhover (the only way to prevent the loop) and found a new home for it: I added this line to the code, just before calling ui.interact():
Code: Select all
ui.timer(0.1, renpy.restart_interaction)
I've gone on, trying variations of this idea, like calling itemPopup (the function that creates the "popup", if approrpriate), and later trying to return some value from itemPopup itself... I was getting some strange behaviour, so I have gone for something simpler to trace what's going on: currently I have this line:
Code: Select all
ui.timer(1, lambda: not None, repeat=True)
My first hipotesis has been that the timer would be taking away the focus from the button on each "tick", hence causing the onUnhover call... I tried to take it out, and put: debug("onUnhover") (debug is a character object, and actually he's becomming a really good friend of me
![Laughing :lol:](./images/smilies/icon_lol.gif)
RuntimeError: maximum recursion depth exceeded in cmp
That traceback.txt of more than a thousand lines pops up as soon as I try to enter the shop in the game...
So, in summary, two questions:
-> When is the unhovered callback being called? According to the reference:
but I've seen with my own eyes that it's being called more often than that (and this is a problem because I was relying on it to know when does something actually loses focus)unhovered - A function that is called with no arguments when the button loses focus.
-> Is there any way to find out from the code which widget has focus? With that, I would have enough to avoid all the misschief that the unhovered is bringing.
I have failed to meet my deadlines so many times I'm not announcing my projects anymore. Whatever I'm working on, it'll be released when it is ready ![Razz :P](./images/smilies/icon_razz.gif)
![Razz :P](./images/smilies/icon_razz.gif)
- PyTom
- Ren'Py Creator
- Posts: 16097
- Joined: Mon Feb 02, 2004 10:58 am
- Completed: Moonlight Walks
- Projects: Ren'Py
- IRC Nick: renpytom
- Github: renpytom
- itch: renpytom
- Location: Kings Park, NY
- Contact:
Re: Where is the mouse?
Unhovered is called at least once per displayable per interaction-restart. The best way is to curry information into the hover and unhover callbacks, and use that to see if what you want is actually hovered. If it is, then you can make use of it.
(Perhaps I should introduce focused and unfocused methods that have saner semantics.)
(Perhaps I should introduce focused and unfocused methods that have saner semantics.)
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom(When was the last time you backed up your game?)
Software > Drama • https://www.patreon.com/renpytom
-
- Veteran
- Posts: 359
- Joined: Sat Feb 25, 2006 11:09 am
- Location: Sant Cugat del Vallès (Barcelona, Spain)
- Contact:
Re: Where is the mouse?
That explains many things.PyTom wrote:Unhovered is called at least once per displayable per interaction-restart.
I'm not sure what "to curry information" means (I know my English is not perfect, buy I'm used to curry only some dishes) but anyway; after some loops and many calls to is_focused(), the UI is behaving as expected.PyTom wrote:The best way is to curry information into the hover and unhover callbacks, and use that to see if what you want is actually hovered. If it is, then you can make use of it.
Perhaps? Well, I guess it's not usual among Ren'py games to mess up with hovering the way I did, but for these few cases having more "previsible" callbacks to handle this would be really useful. In the meanwhile, I'd suggest updating the reference better explaining when the unhovered callback is called. Maybe adding you own words "Unhovered is called at least once per displayable per interaction-restart." would warn other users before getting themselves into the nightmare I've gone through.PyTom wrote:(Perhaps I should introduce focused and unfocused methods that have saner semantics.)
Well, the best part of all this is how well I feel now that it's done and finished! ^^
I have failed to meet my deadlines so many times I'm not announcing my projects anymore. Whatever I'm working on, it'll be released when it is ready ![Razz :P](./images/smilies/icon_razz.gif)
![Razz :P](./images/smilies/icon_razz.gif)
Re: Where is the mouse?
Currying is the practice of collapsing parameters into the function itself. So you might have a function which takes parameters A and B, and returns X; if you curry A into the function, then you're effectively pre-setting the value of A, and you're left with a [curried] function which takes parameter B, and returns X. You could further curry B in and just have a function which generates X when you call it.herenvardo wrote: I'm not sure what "to curry information" means (I know my English is not perfect, buy I'm used to curry only some dishes) but anyway; after some loops and many calls to is_focused(), the UI is behaving as expected.
Server error: user 'Jake' not found
-
- Eileen-Class Veteran
- Posts: 1153
- Joined: Mon Jul 07, 2003 4:57 pm
- Completed: Elven Relations, Cloud Fairy, When I Rule The World
- Tumblr: alextfish
- Skype: alextfish
- Location: Cambridge, UK
- Contact:
Re: Where is the mouse?
Specifically, the way to do it in Ren'Py is using renpy.curry, like this:
The version where you curry all the parameters into the function (like return12() above) is useful when you need functions which take no input arguments, such as the hovered= and clicked= parameters of buttons.
If there's a function which you're only ever going to call curried, then you can wrap it up like this:PyTom explained the "@renpy.curry" syntax to me in this post.
Code: Select all
python:
def sum(A, B):
return A+B
curried_sum = renpy.curry(sum)
add3 = curried_sum(3)
narrator("5 plus 3 is %d" % add3(5))
return12 = curried_sum(6, 6)
narrator("There are %d months in the year" % return12())
If there's a function which you're only ever going to call curried, then you can wrap it up like this:
Code: Select all
python:
@renpy.curry
def UnHoverCallback(object=None):
if object is not None:
# do something to hide things
I released 3 VNs, many moons ago: Elven Relations (IntRenAiMo 2007), When I Rule The World (NaNoRenO 2005), and Cloud Fairy (the Cute Light & Fluffy Project, 2009).
More recently I designed the board game Steam Works (published in 2015), available from a local gaming store near you!
More recently I designed the board game Steam Works (published in 2015), available from a local gaming store near you!
-
- Veteran
- Posts: 359
- Joined: Sat Feb 25, 2006 11:09 am
- Location: Sant Cugat del Vallès (Barcelona, Spain)
- Contact:
Re: Where is the mouse?
Thanks for your replies, they are quite interesting. However, I think this is, in essence, what I'm already doing with lambdas, having code like:
So I now know a new word for something I had already been doing for a while ![Razz :P](./images/smilies/icon_razz.gif)
EDIT: Wooo, I now understand what "renpy.curried_call_in_new_context" stands for![Laughing :lol:](./images/smilies/icon_lol.gif)
Code: Select all
def onHovering(hover, list, index):
# some code to check what's hovered and what's not
# ... some more irrelevant code
ui.textbutton(text, size=14, size_group=id,
clicked =ui.returns(("c"+id, i)),
hovered =lambda: onHovering(True, id, i)
unhovered=lambda: onHovering(False, id, i)
![Razz :P](./images/smilies/icon_razz.gif)
EDIT: Wooo, I now understand what "renpy.curried_call_in_new_context" stands for
![Laughing :lol:](./images/smilies/icon_lol.gif)
I have failed to meet my deadlines so many times I'm not announcing my projects anymore. Whatever I'm working on, it'll be released when it is ready ![Razz :P](./images/smilies/icon_razz.gif)
![Razz :P](./images/smilies/icon_razz.gif)
- PyTom
- Ren'Py Creator
- Posts: 16097
- Joined: Mon Feb 02, 2004 10:58 am
- Completed: Moonlight Walks
- Projects: Ren'Py
- IRC Nick: renpytom
- Github: renpytom
- itch: renpytom
- Location: Kings Park, NY
- Contact:
Re: Where is the mouse?
Note that you can't use lambdas in code that's expected to be saved. (While you can use curries.)
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom(When was the last time you backed up your game?)
Software > Drama • https://www.patreon.com/renpytom
Who is online
Users browsing this forum: Bing [Bot]