@@ -15,7 +15,7 @@ class Session:
1515 A bool indicating whether or not the session should try to remove reactions after they have been pressed.
1616 """
1717
18- def __init__ (self ,* , timeout : int = 180 , try_remove : bool = True ):
18+ def __init__ (self , * , timeout : int = 180 , try_remove : bool = True ):
1919 self ._buttons = {}
2020 self ._gather_buttons ()
2121
@@ -32,8 +32,14 @@ def __init_subclass__(cls, **kwargs):
3232
3333 def _gather_buttons (self ):
3434 for _ , member in inspect .getmembers (self ):
35- if hasattr (member , '__button__' ):
36- self ._buttons [member .__button__ [0 ]] = member .__button__ [1 ]
35+ if hasattr (member , '__button__' ): # Check if the member is a button...
36+ self ._buttons [member .__button__ [2 ], member .__button__ [0 ]] = member .__button__ [1 ] # pos, key, value
37+
38+ def sort_buttons (self , * , buttons : dict = None ):
39+ if not buttons :
40+ buttons = self .buttons
41+
42+ return {k [1 ]: v for k , v in sorted (buttons .items (), key = lambda t : t [0 ])}
3743
3844 async def start (self , ctx , page = None ):
3945 """Start the session with the given page.
@@ -57,14 +63,17 @@ async def start(self, ctx, page=None):
5763 self ._session_task = ctx .bot .loop .create_task (self ._session (ctx ))
5864
5965 async def _session (self , ctx ):
66+ self .buttons = self .sort_buttons ()
67+
6068 for reaction in self .buttons .keys ():
6169 ctx .bot .loop .create_task (self ._add_reaction (reaction ))
6270
6371 while True :
6472 try :
65- payload = await ctx .bot .wait_for ('raw_reaction_add' , timeout = self .timeout , check = lambda _ : self .check (_ )(ctx ))
73+ payload = await ctx .bot .wait_for ('raw_reaction_add' , timeout = self .timeout ,
74+ check = lambda _ : self .check (_ )(ctx ))
6675 except asyncio .TimeoutError :
67- return await self .cancel (ctx )
76+ return ctx . bot . loop . create_task ( self .cancel (ctx ) )
6877
6978 if self ._try_remove :
7079 try :
@@ -110,6 +119,7 @@ def inner(ctx):
110119 elif payload .user_id != ctx .author .id :
111120 return False
112121 return True
122+
113123 return inner
114124
115125
@@ -145,17 +155,17 @@ class Paginator(Session):
145155 Only available when embed=True. The thumbnail URL to set for the embeded pages.
146156 """
147157
148- def __init__ (self , * , title : str = '' , length : int = 10 , entries : list = None ,
149- extra_pages : list = None , prefix : str = '' , suffix : str = '' , format : str = '' ,
150- colour : Union [int , discord .Colour ]= discord .Embed .Empty ,
151- color : Union [int , discord .Colour ]= discord .Embed .Empty , use_defaults : bool = True , embed : bool = True ,
152- joiner : str = '\n ' , timeout : int = 180 , thumbnail : str = None ):
158+ def __init__ (self , * , title : str = '' , length : int = 10 , entries : list = None ,
159+ extra_pages : list = None , prefix : str = '' , suffix : str = '' , format : str = '' ,
160+ colour : Union [int , discord .Colour ] = discord .Embed .Empty ,
161+ color : Union [int , discord .Colour ] = discord .Embed .Empty , use_defaults : bool = True , embed : bool = True ,
162+ joiner : str = '\n ' , timeout : int = 180 , thumbnail : str = None ):
153163 super ().__init__ ()
154- self ._defaults = {'⏮' : partial (self ._default_indexer , 'start' ),
155- '◀' : partial (self ._default_indexer , - 1 ),
156- '⏹' : partial (self ._default_indexer , 'stop' ),
157- '▶' : partial (self ._default_indexer , + 1 ),
158- '⏭' : partial (self ._default_indexer , 'end' )}
164+ self ._defaults = {( 0 , '⏮' ) : partial (self ._default_indexer , 'start' ),
165+ ( 1 , '◀' ) : partial (self ._default_indexer , - 1 ),
166+ ( 2 , '⏹' ) : partial (self ._default_indexer , 'stop' ),
167+ ( 3 , '▶' ) : partial (self ._default_indexer , + 1 ),
168+ ( 4 , '⏭' ) : partial (self ._default_indexer , 'end' )}
159169
160170 self .buttons = {}
161171
@@ -233,14 +243,17 @@ async def _session(self, ctx):
233243 else :
234244 self .buttons = self ._buttons
235245
246+ self .buttons = self .sort_buttons ()
247+
236248 for reaction in self .buttons .keys ():
237249 ctx .bot .loop .create_task (self ._add_reaction (reaction ))
238250
239251 while True :
240252 try :
241- payload = await ctx .bot .wait_for ('raw_reaction_add' , timeout = self .timeout , check = lambda _ : self .check (_ )(ctx ))
253+ payload = await ctx .bot .wait_for ('raw_reaction_add' , timeout = self .timeout ,
254+ check = lambda _ : self .check (_ )(ctx ))
242255 except asyncio .TimeoutError :
243- return await self .cancel (ctx )
256+ return ctx . bot . loop . create_task ( self .cancel (ctx ) )
244257
245258 if self ._try_remove :
246259 try :
@@ -281,24 +294,28 @@ async def _default_indexer(self, control, ctx):
281294 await self .page .edit (content = self ._pages [self ._index ])
282295
283296
284- def button (emoji : str ):
297+ def button (emoji : str , * , position : int = 666 ):
285298 """A decorator that adds a button to your interactive session class.
286299
287300 Parameters
288301 -----------
289302 emoji: str
290303 The emoji to use as a button. This could be a unicode endpoint or in name:id format,
291- for custom emojis
304+ for custom emojis.
305+ position: int
306+ The position to inject the button into.
292307
293308 Raises
294309 -------
295310 TypeError
296311 The button callback is not a coroutine.
297312 """
313+
298314 def deco (func ):
299315 if not asyncio .iscoroutinefunction (func ):
300316 raise TypeError ('Button callback must be a coroutine.' )
301317
302- func .__button__ = (emoji , func )
318+ func .__button__ = (emoji , func , position )
303319 return func
320+
304321 return deco
0 commit comments