osb/source/windowing/StarListWidget.cpp

263 lines
6.9 KiB
C++
Raw Normal View History

2023-06-20 04:33:09 +00:00
#include "StarListWidget.hpp"
#include "StarGuiReader.hpp"
#include "StarJsonExtra.hpp"
#include "StarRandom.hpp"
#include "StarImageWidget.hpp"
#include "StarAssets.hpp"
#include "StarRoot.hpp"
namespace Star {
ListWidget::ListWidget(Json const& schema) : m_schema(schema) {
m_selectedItem = NPos;
m_columns = 1;
setSchema(m_schema);
updateSizeAndPosition();
}
ListWidget::ListWidget() {
m_selectedItem = NPos;
m_columns = 1;
updateSizeAndPosition();
}
RectI ListWidget::relativeBoundRect() const {
if (m_fillDown)
return RectI::withSize(relativePosition() - Vec2I(0, size()[1]), size());
else
return RectI::withSize(relativePosition(), size());
}
void ListWidget::setCallback(WidgetCallbackFunc callback) {
m_callback = move(callback);
}
bool ListWidget::sendEvent(InputEvent const& event) {
if (!m_visible)
return false;
for (size_t i = m_members.size(); i != 0; --i) {
auto child = m_members[i - 1];
if (child->sendEvent(event)
|| (event.is<MouseButtonDownEvent>() && child->inMember(*context()->mousePosition(event))
&& event.get<MouseButtonDownEvent>().mouseButton == MouseButton::Left)) {
setSelected(i - 1);
return true;
}
setHovered(i - 1, event.is<MouseMoveEvent>() && child->inMember(*context()->mousePosition(event)));
}
return false;
}
void ListWidget::setSchema(Json const& schema) {
clear();
m_schema = schema;
try {
m_selectedBG = schema.getString("selectedBG", "");
m_unselectedBG = schema.getString("unselectedBG", "");
m_hoverBG = schema.getString("hoverBG", "");
m_disabledBG = schema.getString("disabledBG", "");
if (m_disabledBG.empty() && !m_unselectedBG.empty())
m_disabledBG = m_unselectedBG + Root::singleton().assets()->json("/interface.config:disabledButton").toString();
m_spacing = jsonToVec2I(schema.get("spacing"));
m_memberSize = jsonToVec2I(schema.get("memberSize"));
} catch (JsonException const& e) {
throw GuiException(strf("Missing required value in map: %s", outputException(e, false)));
}
updateSizeAndPosition();
}
WidgetPtr ListWidget::addItem() {
auto newItem = constructWidget();
addChild(strf("%d", Random::randu64()), newItem);
updateSizeAndPosition();
return newItem;
}
WidgetPtr ListWidget::addItem(size_t at) {
auto newItem = constructWidget();
addChildAt(strf("%d", Random::randu64()), newItem, at);
updateSizeAndPosition();
if (m_selectedItem != NPos && at <= m_selectedItem)
setSelected(m_selectedItem + 1);
return newItem;
}
WidgetPtr ListWidget::addItem(WidgetPtr existingItem) {
addChild(strf("%d", Random::randu64()), existingItem);
updateSizeAndPosition();
return existingItem;
}
WidgetPtr ListWidget::constructWidget() {
WidgetPtr newItem = make_shared<Widget>();
m_reader.construct(m_schema.get("listTemplate"), newItem.get());
newItem->setSize(m_memberSize);
m_doScissor ? newItem->enableScissoring() : newItem->disableScissoring();
return newItem;
}
void ListWidget::updateSizeAndPosition() {
int rows = m_members.size() % m_columns ? m_members.size() / m_columns + 1 : m_members.size() / m_columns;
for (size_t i = 0; i < m_members.size(); i++) {
Vec2I currentOffset;
int col = i % m_columns;
int row = rows - (i / m_columns) - 1;
if (m_fillDown)
row -= rows;
currentOffset = Vec2I((m_memberSize[0] + m_spacing[0]) * col, (m_memberSize[1] + m_spacing[1]) * row);
if (!m_fillDown)
currentOffset[1] += m_spacing[1];
m_members[i]->setPosition(currentOffset);
}
if (m_members.size()) {
auto width = (m_memberSize[0] + m_spacing[0]) * m_columns;
auto height = (m_memberSize[1] + m_spacing[1]) * rows;
setSize(Vec2I(width, height));
} else {
setSize(Vec2I());
}
}
void ListWidget::setEnabled(size_t pos, bool enabled) {
if (pos != NPos && pos < listSize()) {
if (enabled) {
m_disabledItems.remove(pos);
if (auto bgWidget = itemAt(pos)->fetchChild<ImageWidget>("background"))
bgWidget->setImage(pos == m_selectedItem ? m_selectedBG : m_unselectedBG);
} else {
m_disabledItems.add(pos);
if (m_selectedItem == pos)
clearSelected();
if (auto bgWidget = itemAt(pos)->fetchChild<ImageWidget>("background"))
bgWidget->setImage(m_disabledBG);
}
}
}
void ListWidget::setHovered(size_t pos, bool hovered) {
if (m_hoverBG == "")
return;
if (pos != m_selectedItem && pos < listSize() && !m_disabledItems.contains(pos)) {
if (auto bgWidget = itemAt(pos)->fetchChild<ImageWidget>("background")) {
if (hovered)
bgWidget->setImage(m_hoverBG);
else
bgWidget->setImage(m_unselectedBG);
}
}
}
void ListWidget::setSelected(size_t pos) {
if ((m_selectedItem != NPos) && (m_selectedItem < listSize())) {
if (auto bgWidget = selectedWidget()->fetchChild<ImageWidget>("background"))
bgWidget->setImage(m_unselectedBG);
}
if (!m_disabledItems.contains(pos) && m_selectedItem != pos) {
m_selectedItem = pos;
if (m_callback)
m_callback(this);
}
if (m_selectedItem != NPos) {
if (auto bgWidget = selectedWidget()->fetchChild<ImageWidget>("background"))
bgWidget->setImage(m_selectedBG);
}
}
void ListWidget::clearSelected() {
setSelected(NPos);
}
void ListWidget::setSelectedWidget(WidgetPtr selected) {
auto offset = itemPosition(selected);
if (offset == NPos) {
throw GuiException("Attempted to select item not in list.");
}
setSelected(offset);
}
void ListWidget::registerMemberCallback(String const& name, WidgetCallbackFunc const& callback) {
m_reader.registerCallback(name, callback);
}
void ListWidget::setFillDown(bool fillDown) {
m_fillDown = fillDown;
}
void ListWidget::setColumns(uint64_t columns) {
m_columns = columns;
}
void ListWidget::removeItem(size_t at) {
removeChildAt(at);
if (m_selectedItem == at)
setSelected(NPos);
else if (m_selectedItem != NPos && m_selectedItem > at)
setSelected(m_selectedItem - 1);
updateSizeAndPosition();
}
void ListWidget::removeItem(WidgetPtr item) {
auto offset = itemPosition(item);
if (offset == NPos) {
throw GuiException("Attempted to remove item not in list.");
}
removeItem(offset);
}
void ListWidget::clear() {
setSelected(NPos);
removeAllChildren();
updateSizeAndPosition();
}
size_t ListWidget::selectedItem() const {
return m_selectedItem;
}
size_t ListWidget::itemPosition(WidgetPtr item) const {
size_t offset = NPos;
for (size_t i = 0; i < m_members.size(); ++i) {
if (m_members[i] == item) {
offset = i;
break;
}
}
return offset;
}
WidgetPtr ListWidget::itemAt(size_t n) const {
if (n < m_members.size()) {
return m_members[n];
} else {
return {};
}
}
WidgetPtr ListWidget::selectedWidget() const {
return itemAt(m_selectedItem);
}
List<WidgetPtr> const& ListWidget::list() const {
return m_members;
}
size_t ListWidget::listSize() const {
return numChildren();
}
}