// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "ListViewWithArrows.hpp"
#include "TextFixedSize.hpp"
#include "ImageBox.hpp"
#include <InputEvent.hpp>
namespace gui
{
ListViewWithArrows::ListViewWithArrows(Item *parent,
unsigned int x,
unsigned int y,
unsigned int w,
unsigned int h,
std::shared_ptr<ListItemProvider> prov)
: Rect{parent, x, y, w, h}, ListViewEngine(std::move(prov))
{
this->setEdges(RectangleEdge::None);
createLayout();
body->borderCallback = [this](const InputEvent &inputEvent) -> bool {
if (!inputEvent.isShortRelease()) {
return false;
}
if (inputEvent.is(KeyCode::KEY_UP) && pageLoaded) {
return this->requestPreviousPage();
}
else if (inputEvent.is(KeyCode::KEY_DOWN) && pageLoaded) {
return this->requestNextPage();
}
else {
return false;
}
};
inputCallback = [&](Item &item, const InputEvent &event) { return body->onInput(event); };
focusChangedCallback = [this]([[maybe_unused]] Item &item) -> bool {
if (focus) {
setFocus();
}
else {
setFocusItem(nullptr);
}
return true;
};
body->dimensionChangedCallback = [&](gui::Item &, const BoundingBox &newDim) -> bool {
if (listOverlay->lastBox->visible && direction == listview::Direction::Top) {
if (startIndex > 1 && listOverlay->firstBox->visible) {
startIndex += 1;
}
if (startIndex == 1 && !listOverlay->firstBox->visible) {
startIndex = 0;
}
}
currentPageSize = body->getVisibleChildrenCount();
return true;
};
applyScrollCallbacks();
type = gui::ItemType::LIST;
}
void ListViewWithArrows::createLayout()
{
widgetBody = new VBox(this, 0, 0, widgetArea.w, widgetArea.h);
widgetBody->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
widgetBody->setEdges(RectangleEdge::None);
listOverlay = new VThreeBox<VBox, VBox, VBox>(widgetBody, 0, 0, 0, 0);
listOverlay->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
listOverlay->setEdges(RectangleEdge::None);
listOverlay->firstBox = new VBox(listOverlay);
listOverlay->firstBox->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
listOverlay->firstBox->setEdges(RectangleEdge::None);
listOverlay->firstBox->setVisible(false);
arrowTop = new ImageBox(listOverlay->firstBox, new Image("bell_arrow_top_W_M"));
arrowTop->setMinimumSizeToFitImage();
listOverlay->centerBox = new VBox(listOverlay);
listOverlay->centerBox->setAlignment(Alignment(gui::Alignment::Horizontal::Center));
listOverlay->centerBox->setEdges(RectangleEdge::None);
body = new VBox(listOverlay->centerBox);
body->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
body->setEdges(RectangleEdge::None);
listOverlay->lastBox = new VBox(listOverlay);
listOverlay->lastBox->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
listOverlay->lastBox->setEdges(RectangleEdge::None);
listOverlay->lastBox->setVisible(false);
arrowDown = new ImageBox(listOverlay->lastBox, new Image("bell_arrow_down_W_M"));
arrowDown->setMinimumSizeToFitImage();
}
void ListViewWithArrows::applySizeRestrictions(unsigned int w,
unsigned int h,
unsigned int outerLayoutsH,
int outerLayoutsMargin)
{
listOverlay->setMinimumSize(w, h);
body->setMaximumSize(w, h);
listOverlay->firstBox->setMinimumSize(w, outerLayoutsH);
listOverlay->centerBox->setMaximumSize(w, h);
listOverlay->centerBox->setMargins(Margins(0, outerLayoutsMargin, 0, outerLayoutsMargin));
listOverlay->lastBox->setMinimumSize(w, outerLayoutsH);
widgetBody->resizeItems();
}
void ListViewWithArrows::setListTitle(const std::string &title)
{
titleBody = new TextFixedSize(listOverlay->firstBox);
titleBody->drawUnderline(false);
titleBody->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
titleBody->setFont(style::window::font::large);
titleBody->setMinimumSize(listOverlay->firstBox->widgetMinimumArea.w,
listOverlay->firstBox->widgetMinimumArea.h);
titleBody->setEdges(RectangleEdge::None);
titleBody->setEditMode(EditMode::Browse);
titleBody->setText(title);
body->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
listOverlay->firstBox->setVisible(true);
listOverlay->resizeItems();
// Second resize is needed as we need to first apply max size for center box and next extra margins.
listOverlay->resizeItems();
arrowTop->setVisible(false);
titleBody->setVisible(true);
listOverlay->firstBox->resizeItems();
}
void ListViewWithArrows::setListTitleFont(const UTF8 &fontName)
{
titleBody->setFont(fontName);
}
void ListViewWithArrows::applyScrollCallbacks()
{
updateScrollCallback = [this](ListViewScrollUpdateData data) {
auto elementsOnPage = listOverlay->centerBox->widgetArea.h / data.elementMinimalSpaceRequired;
if (boundaries == Boundaries::Continuous) {
if (elementsOnPage == data.elementsCount) {
listOverlay->firstBox->setVisible(true);
listOverlay->lastBox->setVisible(false);
}
else if (elementsOnPage < data.elementsCount) {
listOverlay->firstBox->setVisible(true);
listOverlay->lastBox->setVisible(true);
}
else {
listOverlay->firstBox->setVisible(false);
listOverlay->lastBox->setVisible(false);
}
}
else if (boundaries == Boundaries::Fixed) {
if (elementsOnPage + data.startIndex < data.elementsCount) {
listOverlay->lastBox->setVisible(true);
}
else {
listOverlay->lastBox->setVisible(false);
}
if (data.startIndex == 0 && titleBody) {
titleBody->setVisible(true);
arrowTop->setVisible(false);
listOverlay->firstBox->setVisible(true);
}
else if (data.startIndex > 1) {
if (titleBody) {
titleBody->setVisible(false);
}
arrowTop->setVisible(true);
listOverlay->firstBox->setVisible(true);
}
else {
listOverlay->firstBox->setVisible(false);
}
}
listOverlay->resizeItems();
// Second resize is needed as we need to first apply max size for center box and next extra margins.
listOverlay->resizeItems();
};
}
void ListViewWithArrows::setFocus()
{
if (!focus) {
return;
}
setFocusItem(body);
ListViewEngine::setFocus();
}
void ListViewWithArrows::setAlignment(const Alignment &value)
{
if (body->getAlignment() != value) {
body->setAlignment(value);
}
}
bool ListViewWithArrows::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim)
{
Rect::onDimensionChanged(oldDim, newDim);
body->setSize(body->getWidth(), newDim.h);
return true;
}
} /* namespace gui */