// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md #pragma once #include #include "Layout.hpp" #include "Rect.hpp" #include #include "LayoutSizeStore.hpp" #include namespace gui { class BoxLayout : public Rect, Layout { protected: struct BoxElement { BoxElement(Item *item) : item{item}, noUpdate{false} {}; Item *item; bool noUpdate; }; template Length sizeUsed(Item *box, Area area = Area::Min) { Length sum = 0; std::for_each(box->children.begin(), box->children.end(), [&](auto &child) { sum += child->visible ? child->area(area).size(axis) + child->getMargins().getSumInAxis(axis) : 0; }); return sum; }; template Length sizeUsedWithoutElem(Item *box, Item *elem, Area area = Area::Min) { Length sum = 0; std::for_each(box->children.begin(), box->children.end(), [&](auto &child) { if (child != elem) { sum += child->visible ? child->area(area).size(axis) + child->getMargins().getSumInAxis(axis) : 0; } }); return sum; }; template Length sizeLeft(Item *box, Area area = Area::Min) { return (sizeUsed(box, area) >= box->getSize(axis)) ? 0 : box->getSize(axis) - sizeUsed(box, area); }; template Length sizeLeftWithoutElem(Item *box, Item *elem, Area area = Area::Min) { return (sizeUsedWithoutElem(box, elem, area) >= box->getSize(axis)) ? 0 : box->getSize(axis) - sizeUsedWithoutElem(box, elem, area); }; template void resizeItems(); template [[nodiscard]] Position getAxisAlignmentValue(Position calcPos, Length calcSize, Item *el); std::list outOfDrawAreaItems; void addToOutOfDrawAreaList(Item *item); void addFromOutOfDrawAreaList(); virtual void resizeItems(); bool reverseOrder = false; template [[nodiscard]] Length calculateElemResize(Item *el, Length &toSplit); template [[nodiscard]] Length calculateElemAxisSize(Item *el, Length calculatedResize, Length &toSplit); template [[nodiscard]] Length calculateElemOrtAxisSize(Item *el); template [[nodiscard]] Position calculateElemAxisPosition(Item *el, Length axisItemSize, Position &startingPosition, Position &leftPosition); template [[nodiscard]] Position calculateElemOrtAxisPosition(Item *el, Length orthogonalItemSize); Item *getLastVisibleElement(); /// get next navigation item including `from` item, ecludes not visible items and not acvite items std::list::iterator nextNavigationItem(std::list::iterator from); public: BoxLayout(); BoxLayout(Item *parent, const uint32_t &x, const uint32_t &y, const uint32_t &w, const uint32_t &h); bool onInput(const InputEvent &inputEvent) override; virtual bool onFocus(bool state) override; virtual ~BoxLayout() = default; // virtual methods from Item void setAlignment(const Alignment &value) override; void addWidget(gui::Item *item) override; bool removeWidget(Item *item) override; bool erase(Item *item) override; void erase() override; [[nodiscard]] bool empty() const noexcept; /// add item if it will fit in box, return true on success /// axis sets direction to define space left in container template void addWidget(Item *item); /// set navigation from last to fist element in box virtual void setNavigation(); std::list::iterator getNavigationFocusedItem(); [[nodiscard]] unsigned int getFocusItemIndex() const; [[nodiscard]] unsigned int getVisibleChildrenCount(); /// If requested causes box to change its structure parent may need to do some actions via this callback. std::function parentOnRequestedResizeCallback = nullptr; void setVisible(bool value) override; /// set visible but from previous scope... (page, element etc) void setVisible(bool value, bool previous); void setReverseOrder(bool value); [[nodiscard]] bool getReverseOrder(); /// callback for situaton when we reached top/bottom/left/right of box /// if we want to do sth special (i.e. request new items) std::function borderCallback = nullptr; /// set focus on specified box element bool setFocusOnElement(unsigned int elementNumber); void setFocusOnLastElement(); template Size handleRequestResize(const Item *, Length request_w, Length request_h); bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override; void handleContentChanged() override; /// Get primary sizes used in axis dominant layouts Length getPrimarySizeLeft(); Length getPrimarySize(); }; class HBox : public BoxLayout { public: void resizeItems() override; HBox(); HBox(Item *parent, const uint32_t &x = 0, const uint32_t &y = 0, const uint32_t &w = 0, const uint32_t &h = 0); virtual ~HBox() = default; virtual void addWidget(Item *item) override; Size handleRequestResize(const Item *, Length request_w, Length request_h) override; }; class VBox : public BoxLayout { public: void resizeItems() override; VBox(); VBox(Item *parent, const uint32_t &x = 0, const uint32_t &y = 0, const uint32_t &w = 0, const uint32_t &h = 0); virtual ~VBox() = default; virtual void addWidget(Item *item) override; Size handleRequestResize(const Item *, Length request_w, Length request_h) override; }; } /* namespace gui */