class LayoutMixin(core.ObjectMixin, widgets.LayoutItemMixin):
    def __init__(self, *args, margin=None, **kwargs):
        self._next_container = None
        self._stack = []
        super().__init__(*args, **kwargs)
        if margin is not None:
            self.set_margin(margin)
    @overload
    def __getitem__(
        self, index: slice
    ) -> listdelegators.ListDelegator[widgets.QWidget | widgets.QLayout]:
        ...
    @overload
    def __getitem__(self, index: int | str) -> widgets.QWidget | widgets.QLayout:
        ...
    def __getitem__(
        self, index: str | int | slice
    ) -> (
        widgets.QWidget
        | widgets.QLayout
        | listdelegators.ListDelegator[widgets.QWidget | widgets.QLayout]
    ):
        match index:
            case int():
                if index < 0:
                    index + self.count()
                if index < 0 or index >= self.count():
                    raise IndexError(index)
                item = self.itemAt(index)
                return i if (i := item.widget()) is not None else item.layout()
            case str():
                if (item := self.find_child(typ=core.QObject, name=index)) is not None:
                    return item
                raise KeyError(index)
            case slice():
                stop = index.stop or self.count()
                rng = range(index.start or 0, stop, index.step or 1)
                widgets = [self[i] for i in rng]
                return listdelegators.ListDelegator(widgets, parent=self)
            case _:
                raise TypeError(index)
    def __setitem__(self, key, value):
        if self._container != self:
            self._container.__setitem__(key, value)
    def __delitem__(self, item: int | widgets.QLayoutItem):
        if isinstance(item, int):
            item = self.itemAt(item)
        self.removeItem(item)
        item.deleteLater()
    def __len__(self) -> int:
        return self.count()
    def __iter__(self) -> Iterator[widgets.QWidget | widgets.QLayout | None]:
        return iter(self[i] for i in range(self.count()))
    def __contains__(self, item: widgets.QWidget | widgets.QLayoutItem):
        return self.indexOf(item) >= 0
    def __iadd__(self, item, *args, **kwargs):
        self.add(item, *args, **kwargs)
        return self
    def _get_map(self):
        maps = super()._get_map()
        maps |= {"sizeConstraint": SIZE_CONSTRAINT}
        return maps
    def add(self, item, *args, **kwargs):
        match item:
            case widgets.QWidget():
                self._container.addWidget(item, *args, **kwargs)
            case widgets.QLayout():
                self._container.addLayout(item, *args, **kwargs)
            case widgets.QLayoutItem():
                self._container.addItem(item, *args, **kwargs)
            case list():
                for i in item:
                    self._container.add(i, *args, **kwargs)
        return item
    def __enter__(self):
        def enter(item):
            if item._next_container is not None:
                enter(item._next_container)
                item._stack.append(item._next_container)
                item._next_container = None
            return item
        return enter(self)
    def __exit__(self, *_):
        def exit(item):
            if item._stack:
                item = item._stack.pop()
                exit(item)
        exit(self)
    @property
    def _container(self):
        return self._stack[-1] if self._stack else self
    def get_sub_layout(
        self,
        layout: str,
        orientation: constants.OrientationStr | None = None,
        stretch: int | None = None,
        **kwargs,
    ) -> Self:
        from prettyqt import custom_widgets
        CONTEXT_LAYOUTS = dict(
            horizontal=widgets.HBoxLayout,
            vertical=widgets.VBoxLayout,
            grid=widgets.GridLayout,
            form=widgets.FormLayout,
            stacked=widgets.StackedLayout,
            flow=custom_widgets.FlowLayout,
            splitter=widgets.Splitter,
            scroll=widgets.ScrollArea,
            frame=widgets.GroupBox,
        )
        Klass = CONTEXT_LAYOUTS[layout]
        match self._container:
            case widgets.QWidget() if layout == "scroll":
                scroller = Klass(parent=self._container)
                scroller.setWidgetResizable(True)
                widget = widgets.Widget()
                scroller.set_widget(widget)
                new = widget.set_layout(orientation, **kwargs)
            case widgets.QLayout() if layout == "scroll":
                scroller = Klass(parent=self._container)
                scroller.setWidgetResizable(True)
                widget = widgets.Widget()
                scroller.set_widget(widget)
                new = widget.set_layout(orientation, **kwargs)
                self._container.add(new)
            case widgets.QWidget() if layout == "splitter":
                new = Klass(orientation=orientation, parent=self._container, **kwargs)
            case widgets.QLayout() if layout == "splitter":
                new = Klass(orientation=orientation, **kwargs)
                self._container.add(new)
            case widgets.QWidget() if layout == "frame":
                frame = Klass(parent=self._container, **kwargs)
                widget = widgets.Widget()
                new = widget.set_layout(orientation or "horizontal")
                frame.set_layout(new)
            case widgets.QLayout() if layout == "frame":
                frame = Klass(**kwargs)
                widget = widgets.Widget()
                new = widget.set_layout(orientation or "horizontal")
                frame.set_layout(new)
                self._container.add(new)
            case widgets.QMainWindow():
                widget = widgets.Widget(parent=self._container)
                self._container.setCentralWidget(widget)
                new = Klass(widget, **kwargs)
            case widgets.QScrollArea():
                widget = widgets.Widget(parent=self._container)
                self._container.setWidget(widget)
                self._container.setWidgetResizable(True)
                new = widget.set_layout("vertical", **kwargs)
            case widgets.QSplitter():
                widget = widgets.Widget(parent=self._container)
                self._container.addWidget(widget)
                new = Klass(widget, **kwargs)
            case None | widgets.QWidget():
                new = Klass(self._container, **kwargs)
            case widgets.QLayout():
                new = Klass(**kwargs)
                if stretch:
                    self._container.add(new, stretch)
                else:
                    self._container.add(new)
        new._stack = []
        new._next_container = None
        self._next_container = new
        return self
    def item_at(self, pos_or_index: int | core.Point) -> widgets.QLayoutItem:
        match pos_or_index:
            case int():
                return super().itemAt(pos_or_index)
            case core.QPoint():
                for i in range(self.count()):
                    item = self.itemAt(i)
                    if item.geometry().contains(pos_or_index):
                        return item
            case _:
                raise ValueError(pos_or_index)
    def clear(self):
        for i in reversed(range(self.count())):
            self.takeAt(i)
    # def takeAt(self, index: int):
    #     if index < 0:
    #         index = self.count() + index
    #     return super().takeAt(index)
    def get_items(self):
        return [self.itemAt(i) for i in range(self.count())]
    def get_children(
        self,
    ) -> listdelegators.ListDelegator[widgets.QWidget | widgets.QLayout]:
        return listdelegators.ListDelegator(self)
    def set_margin(self, margin: datatypes.MarginsType | None):
        match margin:
            case None:
                self.unsetContentsMargins()
            case _:
                margin = datatypes.to_margins(margin)
                self.setContentsMargins(margin)
    def set_spacing(self, pixels: int):
        self.setSpacing(pixels)
    def set_size_constraint(
        self, mode: SizeConstraintStr | widgets.QLayout.SizeConstraint
    ):
        """Set the size mode of the layout.
        Args:
            mode: size mode for the layout
        """
        self.setSizeConstraint(SIZE_CONSTRAINT.get_enum_value(mode))
    def get_size_constraint(self) -> SizeConstraintStr:
        """Return current size mode.
        Returns:
            size mode
        """
        return SIZE_CONSTRAINT.inverse[self.sizeConstraint()]
    def set_alignment(
        self,
        alignment: constants.AlignmentStr | constants.AlignmentFlag,
        item: widgets.QWidget | widgets.QLayout | None = None,
    ) -> bool:
        """Set the alignment for widget / layout to alignment.
        Returns true if w is found in this layout (not including child layouts).
        Args:
            alignment: alignment for the layout
            item: set alignment for specific child only
        """
        if item is not None:
            return self.setAlignment(item, constants.ALIGNMENTS.get_enum_value(alignment))
        else:
            return self.setAlignment(constants.ALIGNMENTS.get_enum_value(alignment))