osb/source/windowing/StarItemGridWidget.cpp
2023-06-20 14:33:09 +10:00

290 lines
8.3 KiB
C++

#include "StarItemGridWidget.hpp"
#include "StarRoot.hpp"
#include "StarJsonExtra.hpp"
#include "StarAssets.hpp"
namespace Star {
ItemGridWidget::ItemGridWidget(ItemBagConstPtr bag, Vec2I const& dimensions, Vec2I const& spacing, String const& backingImage, unsigned bagOffset)
: ItemGridWidget(bag, dimensions, {spacing[0], 0}, {0, spacing[1]}, backingImage, bagOffset) {}
ItemGridWidget::ItemGridWidget(ItemBagConstPtr bag, Vec2I const& dimensions, Vec2I const& rowSpacing, Vec2I const& columnSpacing, String const& backingImage, unsigned bagOffset)
: m_bagOffset(bagOffset), m_dimensions(dimensions), m_rowSpacing(rowSpacing), m_columnSpacing(columnSpacing), m_backingImage(backingImage) {
m_selectedIndex = 0;
m_progress = 1;
m_drawBackingImageWhenFull = false;
m_drawBackingImageWhenEmpty = true;
m_showDurability = false;
m_highlightEmpty = false;
setItemBag(bag);
auto assets = Root::singleton().assets();
m_itemDraggableArea = jsonToRectI(assets->json("/interface.config:itemDraggableArea"));
Vec2I calculatedSize = {
m_dimensions[0] * m_rowSpacing[0] + m_dimensions[1] * m_columnSpacing[0],
m_dimensions[0] * m_rowSpacing[1] + m_dimensions[1] * m_columnSpacing[1]
};
setSize(calculatedSize.piecewiseMax(m_itemDraggableArea.size()));
disableScissoring();
markAsContainer();
}
ItemBagConstPtr ItemGridWidget::bag() const {
return m_bag;
}
ItemPtr ItemGridWidget::itemAt(Vec2I const& position) const {
auto pos = bagLocationAt(position);
if (pos != NPos && m_bag)
return m_bag->at(pos);
return {};
}
ItemPtr ItemGridWidget::itemAt(size_t index) const {
if (index < m_bag->size())
return m_bag->at(index);
return {};
}
ItemPtr ItemGridWidget::selectedItem() const {
return itemAt(selectedIndex());
}
ItemSlotWidgetPtr ItemGridWidget::itemWidgetAt(Vec2I const& position) const {
auto pos = bagLocationAt(position);
if (pos != NPos)
return m_slots[pos];
return {};
}
ItemSlotWidgetPtr ItemGridWidget::itemWidgetAt(size_t index) const {
if (index < m_slots.size())
return m_slots[index];
return {};
}
Vec2I ItemGridWidget::dimensions() const {
return m_dimensions;
}
size_t ItemGridWidget::itemSlots() const {
return m_dimensions.x() * m_dimensions.y();
}
size_t ItemGridWidget::bagSize() const {
if (!m_bag)
return 0;
return m_bag->size();
}
size_t ItemGridWidget::effectiveSize() const {
return min(itemSlots(), bagSize());
}
size_t ItemGridWidget::bagLocationAt(Vec2I const& position) const {
if (m_bag) {
for (size_t i = 0; i < (m_bag->size() - m_bagOffset) && i < unsigned(m_dimensions[0] * m_dimensions[1]); ++i) {
Vec2I loc = locOfItemSlot(i);
RectI bagItemArea = RectI(m_itemDraggableArea).translated(screenPosition() + loc);
if (bagItemArea.contains(position))
return i + m_bagOffset;
}
}
return NPos;
}
Vec2I ItemGridWidget::positionOfSlot(size_t slotNumber) {
return m_slots.at(slotNumber)->position() + position();
}
bool ItemGridWidget::sendEvent(InputEvent const& event) {
if (m_visible) {
if (auto mouseButton = event.ptr<MouseButtonDownEvent>()) {
if (mouseButton->mouseButton == MouseButton::Left || (m_rightClickCallback && mouseButton->mouseButton == MouseButton::Right)) {
Vec2I mousePos = *context()->mousePosition(event);
for (size_t i = 0; i < (m_bag->size() - m_bagOffset) && i < unsigned(m_dimensions[0] * m_dimensions[1]); ++i) {
Vec2I loc = locOfItemSlot(i);
RectI bagItemArea = RectI(m_itemDraggableArea).translated(screenPosition() + loc);
if (bagItemArea.contains(mousePos)) {
m_selectedIndex = i;
if (mouseButton->mouseButton == MouseButton::Right)
m_rightClickCallback(this);
else
m_callback(this);
return true;
}
}
}
}
}
return false;
}
Vec2I ItemGridWidget::locOfItemSlot(unsigned slot) const {
Vec2I loc = {
(int)slot % (int)m_dimensions[0] * m_rowSpacing[0] + // x contribution from row
(int)slot / (int)m_dimensions[0] * m_columnSpacing[0], // x contribution from column
(m_dimensions[0] - 1) * m_rowSpacing[1] - (int)slot % (int)m_dimensions[0] * m_rowSpacing[1] + // y contribution from row
(m_dimensions[1] - 1) * m_columnSpacing[1] - (int)slot / (int)m_dimensions[0] * m_columnSpacing[1] // y contribution from column
};
return loc;
}
void ItemGridWidget::setCallback(WidgetCallbackFunc callback) {
m_callback = callback;
}
void ItemGridWidget::setRightClickCallback(WidgetCallbackFunc callback) {
m_rightClickCallback = callback;
}
void ItemGridWidget::setItemBag(ItemBagConstPtr bag) {
m_bag = bag;
if (!m_bag)
return;
removeAllChildren();
m_slots.clear();
for (size_t i = 0; i < m_bag->size() - m_bagOffset && i < (unsigned)m_dimensions[0] * m_dimensions[1]; ++i) {
auto itemSlot = make_shared<ItemSlotWidget>(m_bag->at(i), m_backingImage);
addChild(strf("%d", i), itemSlot);
m_slots.append(itemSlot);
itemSlot->setBackingImageAffinity(m_drawBackingImageWhenFull, m_drawBackingImageWhenEmpty);
itemSlot->setProgress(m_progress);
itemSlot->setPosition(locOfItemSlot(i));
itemSlot->showDurability(m_showDurability);
}
m_itemNames = slotItemNames();
}
void ItemGridWidget::setProgress(float progress) {
m_progress = progress;
if (!m_bag)
return;
for (size_t i = 0; i < m_bag->size() - m_bagOffset && i < (unsigned)m_dimensions[0] * m_dimensions[1]; ++i) {
auto itemSlot = m_slots.at(i);
itemSlot->setProgress(m_progress);
}
}
size_t ItemGridWidget::selectedIndex() const {
return m_selectedIndex + m_bagOffset;
}
void ItemGridWidget::updateAllItemSlots() {
if (!m_bag)
return;
for (size_t i = 0; i < m_bag->size() - m_bagOffset && i < (unsigned)m_dimensions[0] * m_dimensions[1]; ++i) {
auto item = m_bag->at(i + m_bagOffset);
auto slot = m_slots.at(i);
slot->setItem(item);
slot->setHighlightEnabled(!item && m_highlightEmpty);
}
}
void ItemGridWidget::updateItemState() {
updateAllItemSlots();
auto newState = slotItemNames();
for (size_t i = 0; i < newState.size(); ++i) {
if (newState[i].empty()) {
m_changedSlots.remove(i);
continue;
}
if (newState[i].compare(m_itemNames[i]) != 0)
m_changedSlots.insert(i);
}
m_itemNames = newState;
}
void ItemGridWidget::indicateChangedSlots() {
for (auto i : m_changedSlots)
m_slots[i]->indicateNew();
}
void ItemGridWidget::setHighlightEmpty(bool highlight) {
m_highlightEmpty = highlight;
}
void ItemGridWidget::clearChangedSlots() {
m_changedSlots.clear();
}
bool ItemGridWidget::slotsChanged() {
return m_changedSlots.size() > 0;
}
HashSet<ItemDescriptor> ItemGridWidget::uniqueItemState() {
HashSet<ItemDescriptor> state;
if (!m_bag)
return state;
for (auto item : m_bag->items()) {
if (item)
state.add(item->descriptor().singular());
}
return state;
}
List<String> ItemGridWidget::slotItemNames() {
List<String> itemNames;
for (auto slot : m_slots) {
if (slot->item())
itemNames.append(slot->item()->name());
else
itemNames.append(String());
}
return itemNames;
}
void ItemGridWidget::setBackingImageAffinity(bool full, bool empty) {
m_drawBackingImageWhenFull = full;
m_drawBackingImageWhenEmpty = empty;
if (!m_bag)
return;
for (size_t i = 0; i < m_bag->size() - m_bagOffset && i < (unsigned)m_dimensions[0] * m_dimensions[1]; ++i) {
auto itemSlot = m_slots.at(i);
itemSlot->setBackingImageAffinity(m_drawBackingImageWhenFull, m_drawBackingImageWhenEmpty);
}
}
void ItemGridWidget::showDurability(bool show) {
m_showDurability = show;
if (!m_bag)
return;
for (size_t i = 0; i < m_bag->size() - m_bagOffset && i < (unsigned)m_dimensions[0] * m_dimensions[1]; ++i) {
auto itemSlot = m_slots.at(i);
itemSlot->showDurability(m_showDurability);
}
}
RectI ItemGridWidget::getScissorRect() const {
auto assets = Root::singleton().assets();
auto durabilityOffset = jsonToVec2I(assets->json("/interface.config:itemIconDurabilityOffset"));
auto itemCountRightAnchor = jsonToVec2I(assets->json("/interface.config:itemCountRightAnchor"));
Vec2I extra = Vec2I(durabilityOffset * -1).piecewiseMax(itemCountRightAnchor * -1).piecewiseMax(Vec2I());
return RectI::withSize(screenPosition() - extra, size() + extra);
}
void ItemGridWidget::renderImpl() {
updateAllItemSlots();
}
}