From 7012cec96a35c925051b3525d1d56372376c3db2 Mon Sep 17 00:00:00 2001 From: DA-344 <108473820+DA-344@users.noreply.github.com> Date: Tue, 6 May 2025 16:43:05 +0200 Subject: [PATCH] fix: LayoutView.__total_children being incorrectly set when adding/removing items from an item --- discord/ui/action_row.py | 10 ++++++++++ discord/ui/container.py | 17 +++++++++++++++++ discord/ui/section.py | 11 +++++++++++ discord/ui/view.py | 2 ++ 4 files changed, 40 insertions(+) diff --git a/discord/ui/action_row.py b/discord/ui/action_row.py index e54522ec6..a72d4db1e 100644 --- a/discord/ui/action_row.py +++ b/discord/ui/action_row.py @@ -268,6 +268,10 @@ class ActionRow(Item[V]): item._view = self._view item._parent = self self._children.append(item) + + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + self._view.__total_children += 1 + return self def remove_item(self, item: Item[Any]) -> Self: @@ -286,6 +290,10 @@ class ActionRow(Item[V]): self._children.remove(item) except ValueError: pass + else: + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + self._view.__total_children -= 1 + return self def get_item_by_id(self, id: int, /) -> Optional[Item[V]]: @@ -314,6 +322,8 @@ class ActionRow(Item[V]): This function returns the class instance to allow for fluent-style chaining. """ + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + self._view.__total_children -= len(self._children) self._children.clear() return self diff --git a/discord/ui/container.py b/discord/ui/container.py index c5890722c..d9eb4f35d 100644 --- a/discord/ui/container.py +++ b/discord/ui/container.py @@ -360,9 +360,17 @@ class Container(Item[V]): else: self.__dispatchable.append(item) + is_layout_view = self._view and getattr(self._view, '__discord_ui_layout_view__', False) + if getattr(item, '__discord_ui_update_view__', False): item._update_children_view(self.view) # type: ignore + if is_layout_view: + self._view.__total_children += len(tuple(item.walk_children())) # type: ignore + else: + if is_layout_view: + self._view.__total_children += 1 # type: ignore + item._view = self.view item._parent = self return self @@ -383,6 +391,12 @@ class Container(Item[V]): self._children.remove(item) except ValueError: pass + else: + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + if getattr(item, '__discord_ui_update_view__', False): + self._view.__total_children -= len(tuple(item.walk_children())) # type: ignore + else: + self._view.__total_children -= 1 return self def get_item_by_id(self, id: int, /) -> Optional[Item[V]]: @@ -411,5 +425,8 @@ class Container(Item[V]): This function returns the class instance to allow for fluent-style chaining. """ + + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + self._view.__total_children -= len(tuple(self.walk_children())) self._children.clear() return self diff --git a/discord/ui/section.py b/discord/ui/section.py index 2d4acdc3a..70c5a778c 100644 --- a/discord/ui/section.py +++ b/discord/ui/section.py @@ -162,6 +162,10 @@ class Section(Item[V]): item._view = self.view item._parent = self self._children.append(item) + + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + self._view.__total_children += 1 + return self def remove_item(self, item: Item[Any]) -> Self: @@ -180,6 +184,10 @@ class Section(Item[V]): self._children.remove(item) except ValueError: pass + else: + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + self._view.__total_children -= 1 + return self def get_item_by_id(self, id: int, /) -> Optional[Item[V]]: @@ -208,6 +216,9 @@ class Section(Item[V]): This function returns the class instance to allow for fluent-style chaining. """ + if self._view and getattr(self._view, '__discord_ui_layout_view__', False): + self._view.__total_children -= len(self._children) + 1 # the + 1 is the accessory + self._children.clear() return self diff --git a/discord/ui/view.py b/discord/ui/view.py index 2217474c5..d8c21354c 100644 --- a/discord/ui/view.py +++ b/discord/ui/view.py @@ -756,6 +756,8 @@ class LayoutView(BaseView): If ``None`` then there is no timeout. """ + __discord_ui_layout_view__: ClassVar[bool] = True + def __init__(self, *, timeout: Optional[float] = 180.0) -> None: super().__init__(timeout=timeout) self.__total_children: int = len(list(self.walk_children()))