Select¶
Step-by-Step¶
A simple example on the use of selects with disnake-compass.
For this example, we implement a select menu with double functionality. Firstly, the select allows you to select one of three slots. After selecting a slot, the select is modified to instead allow you to select a colour. The selected slot and colour are then combined to colour the corresponding square. and register the select.
1
2LEFT = "\N{BLACK LEFT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}"
3MIDDLE = "\N{BLACK CIRCLE FOR RECORD}\N{VARIATION SELECTOR-16}"
4RIGHT = "\N{BLACK RIGHT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}"
5
6SLOT_OPTIONS = [
7 disnake.SelectOption(label="Left", value="left", emoji=LEFT),
8 disnake.SelectOption(label="Middle", value="middle", emoji=MIDDLE),
9 disnake.SelectOption(label="Right", value="right", emoji=RIGHT),
10 disnake.SelectOption(label="Finalise", emoji="\N{WHITE HEAVY CHECK MARK}"),
11]
12
13
14BLACK_SQUARE = "\N{BLACK LARGE SQUARE}"
15BLUE_SQUARE = "\N{LARGE BLUE SQUARE}"
16BROWN_SQUARE = "\N{LARGE BROWN SQUARE}"
17GREEN_SQUARE = "\N{LARGE GREEN SQUARE}"
18PURPLE_SQUARE = "\N{LARGE PURPLE SQUARE}"
19RED_SQUARE = "\N{LARGE RED SQUARE}"
20WHITE_SQUARE = "\N{WHITE LARGE SQUARE}"
21YELLOW_SQUARE = "\N{LARGE YELLOW SQUARE}"
22
23COLOUR_OPTIONS = [
24 disnake.SelectOption(label="Black", value=BLACK_SQUARE, emoji=BLACK_SQUARE),
25 disnake.SelectOption(label="Blue", value=BLUE_SQUARE, emoji=BLUE_SQUARE),
26 disnake.SelectOption(label="Brown", value=BROWN_SQUARE, emoji=BROWN_SQUARE),
27 disnake.SelectOption(label="Green", value=GREEN_SQUARE, emoji=GREEN_SQUARE),
28 disnake.SelectOption(label="Purple", value=PURPLE_SQUARE, emoji=PURPLE_SQUARE),
29 disnake.SelectOption(label="Red", value=RED_SQUARE, emoji=RED_SQUARE),
30 disnake.SelectOption(label="White", value=WHITE_SQUARE, emoji=WHITE_SQUARE),
31 disnake.SelectOption(label="Yellow", value=YELLOW_SQUARE, emoji=YELLOW_SQUARE),
32]
33
34
35@manager.register
36class MySelect(disnake_compass.RichStringSelect):
37 placeholder: str | None = "Please select a square."
38 options: typing.List[disnake.SelectOption] = SLOT_OPTIONS
39
40 slot: str = "0"
41 state: str = "slot"
42 colour_left: str = BLACK_SQUARE
43 colour_middle: str = BLACK_SQUARE
First, we define our slot and colour options (lines 1-31), then inside the button we set the placeholder text and options (line 36-37).
In the custom id we store the slot the user is currently working with (line 39), whether they’re picking a slot or a colour (line 40), and we store the selected colours for the three slots (lines 41-43).
Next, we define the callback:
1
2 async def callback(
3 self, interaction: disnake.MessageInteraction[disnake.Client]
4 ) -> None:
5 assert interaction.values is not None
6 selected = interaction.values[0]
7
8 if self.state == "slot":
9 self.handle_slots(selected)
10
11 else:
12 self.handle_colours(selected)
Tip
Since we’re dealing with a select, inter.values will never be None.
Therefore, the assertion will never raise.
The assertion only serves to help the type checker realise this.
If the selection was a slot, run slot selection logic (lines 5-6). To keep things tidy, we use a separate function for this. Otherwise, run colour selection logic (lines 8-9). Finally we render the new colours and update the select (lines 77-78).
Then we define handle_slots:
1 msg = self.render_colours()
2 component = await self.as_ui_component()
3 await interaction.response.edit_message(msg, components=component)
4
5 def handle_slots(self, selected: str) -> None:
6 if selected == "Finalise":
7 self.disabled = True
8 self.placeholder = "Woo!"
9 return
10
11 self.options = COLOUR_OPTIONS
In case the user wishes to finalize, disable the select (lines 2-5). Otherwise, we update options and display (lines 7-8) and set the slot to the user’s selection and set state to colour (lines 10-11). The select will now enter colour selection mode.
Then we define handle_colours:
1
2 self.slot = selected
3 self.state = "colour"
4
5 def handle_colours(self, selected: str) -> None:
We update the options back to slot selection (line 2), set the colour attribute for the current slot (line 4), and set the state to slot (line 5). The select will now re-enter slot selection mode.
Finally we define render_colours to simply render the three colour squares:
setattr(self, f"colour_{self.slot}", selected)
Source Code¶
1"""A simple example on the use of selects with disnake-compass."""
2
3from __future__ import annotations
4
5import os
6import typing
7
8import disnake
9import disnake_compass
10from disnake.ext import commands
11
12bot = commands.InteractionBot()
13
14manager = disnake_compass.get_manager()
15manager.add_to_client(bot)
16
17
18LEFT = "\N{BLACK LEFT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}"
19MIDDLE = "\N{BLACK CIRCLE FOR RECORD}\N{VARIATION SELECTOR-16}"
20RIGHT = "\N{BLACK RIGHT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}"
21
22SLOT_OPTIONS = [
23 disnake.SelectOption(label="Left", value="left", emoji=LEFT),
24 disnake.SelectOption(label="Middle", value="middle", emoji=MIDDLE),
25 disnake.SelectOption(label="Right", value="right", emoji=RIGHT),
26 disnake.SelectOption(label="Finalise", emoji="\N{WHITE HEAVY CHECK MARK}"),
27]
28
29
30BLACK_SQUARE = "\N{BLACK LARGE SQUARE}"
31BLUE_SQUARE = "\N{LARGE BLUE SQUARE}"
32BROWN_SQUARE = "\N{LARGE BROWN SQUARE}"
33GREEN_SQUARE = "\N{LARGE GREEN SQUARE}"
34PURPLE_SQUARE = "\N{LARGE PURPLE SQUARE}"
35RED_SQUARE = "\N{LARGE RED SQUARE}"
36WHITE_SQUARE = "\N{WHITE LARGE SQUARE}"
37YELLOW_SQUARE = "\N{LARGE YELLOW SQUARE}"
38
39COLOUR_OPTIONS = [
40 disnake.SelectOption(label="Black", value=BLACK_SQUARE, emoji=BLACK_SQUARE),
41 disnake.SelectOption(label="Blue", value=BLUE_SQUARE, emoji=BLUE_SQUARE),
42 disnake.SelectOption(label="Brown", value=BROWN_SQUARE, emoji=BROWN_SQUARE),
43 disnake.SelectOption(label="Green", value=GREEN_SQUARE, emoji=GREEN_SQUARE),
44 disnake.SelectOption(label="Purple", value=PURPLE_SQUARE, emoji=PURPLE_SQUARE),
45 disnake.SelectOption(label="Red", value=RED_SQUARE, emoji=RED_SQUARE),
46 disnake.SelectOption(label="White", value=WHITE_SQUARE, emoji=WHITE_SQUARE),
47 disnake.SelectOption(label="Yellow", value=YELLOW_SQUARE, emoji=YELLOW_SQUARE),
48]
49
50
51@manager.register
52class MySelect(disnake_compass.RichStringSelect):
53 placeholder: str | None = "Please select a square."
54 options: typing.List[disnake.SelectOption] = SLOT_OPTIONS
55
56 slot: str = "0"
57 state: str = "slot"
58 colour_left: str = BLACK_SQUARE
59 colour_middle: str = BLACK_SQUARE
60 colour_right: str = BLACK_SQUARE
61
62 async def callback(
63 self, interaction: disnake.MessageInteraction[disnake.Client]
64 ) -> None:
65 assert interaction.values is not None
66 selected = interaction.values[0]
67
68 if self.state == "slot":
69 self.handle_slots(selected)
70
71 else:
72 self.handle_colours(selected)
73
74 msg = self.render_colours()
75 component = await self.as_ui_component()
76 await interaction.response.edit_message(msg, components=component)
77
78 def handle_slots(self, selected: str) -> None:
79 if selected == "Finalise":
80 self.disabled = True
81 self.placeholder = "Woo!"
82 return
83
84 self.options = COLOUR_OPTIONS
85 self.placeholder = f"Please select a colour for the {selected} square."
86
87 self.slot = selected
88 self.state = "colour"
89
90 def handle_colours(self, selected: str) -> None:
91 self.options = SLOT_OPTIONS
92
93 setattr(self, f"colour_{self.slot}", selected)
94 self.state = "slot"
95
96 def render_colours(self) -> str:
97 return f"{self.colour_left}{self.colour_middle}{self.colour_right}\n"
98
99
100@bot.slash_command()
101async def test_select(interaction: disnake.CommandInteraction[disnake.Client]) -> None:
102 my_select = MySelect()
103 await interaction.response.send_message(
104 my_select.render_colours(),
105 components=await my_select.as_ui_component(),
106 )
107
108
109bot.run(os.getenv("EXAMPLE_TOKEN"))