GUI: Get size and position of grid item from GridItemInfo

This commit is contained in:
av-dx 2021-07-31 00:52:53 +05:30 committed by Eugene Sandulenko
parent 6c2fdec8a8
commit fb9c232f25
2 changed files with 106 additions and 34 deletions

View file

@ -68,7 +68,8 @@ void GridItemWidget::move(int x, int y) {
void GridItemWidget::drawWidget() { void GridItemWidget::drawWidget() {
if (_activeEntry->isHeader) { if (_activeEntry->isHeader) {
g_gui.theme()->drawText(Common::Rect(_x, _y, _x + _w, _y + _h), Common::U32String(_activeEntry->title), ThemeEngine::kStateEnabled, Graphics::kTextAlignLeft); g_gui.theme()->drawFoldIndicator(Common::Rect(_x, _y, _x + _h, _y + _h), _grid->groupExpanded(_activeEntry->entryID));
g_gui.theme()->drawText(Common::Rect(_x + _h, _y, _x + _w, _y + _h), Common::U32String(_activeEntry->title), ThemeEngine::kStateEnabled, Graphics::kTextAlignLeft);
return; return;
} }
int thumbHeight = _grid->getThumbnailHeight(); int thumbHeight = _grid->getThumbnailHeight();
@ -180,25 +181,32 @@ void GridItemWidget::handleMouseMoved(int x, int y, int button) {
} }
void GridItemWidget::handleMouseDown(int x, int y, int button, int clickCount) { void GridItemWidget::handleMouseDown(int x, int y, int button, int clickCount) {
if (isHighlighted && isVisible()) { if (_activeEntry->isHeader) {
_grid->_selectedEntry = nullptr;
}
else if (isHighlighted && isVisible()) {
_grid->_selectedEntry = _activeEntry; _grid->_selectedEntry = _activeEntry;
sendCommand(kItemClicked, 0); sendCommand(kItemClicked, 0);
// Work in progress // Work in progress
// Since user expected to click on "entry" and not the "widget", we // Since user expected to click on "entry" and not the "widget", we
// must open the tray where the user expects it to be, which might // must open the tray where the user expects it to be, which might
// not be at the new widget location. // not be at the new widget location.
int oldX = getAbsX(), oldY = getAbsY(); // TODO: Make a scrollToSelection() function which does this
int offsetY = 0; int offsetY = 0;
if (_y > (_grid->getHeight() - _h - _grid->_trayHeight)) { if (_y > (_grid->getHeight() - _h - _grid->_trayHeight)) {
offsetY = _y - (_grid->getHeight() - _h - _grid->_trayHeight); offsetY = _y - (_grid->getHeight() - _h - _grid->_trayHeight);
sendCommand(kSetPositionCmd, _grid->getScrollPos() + offsetY); sendCommand(kSetPositionCmd, _grid->getScrollPos() + offsetY);
_grid->scrollBarRecalc();
_grid->markAsDirty(); _grid->markAsDirty();
_grid->draw(); _grid->draw();
} }
_grid->openTray(oldX, oldY - offsetY + _h, _activeEntry->entryID);
} }
} }
void GridItemWidget::handleMouseUp(int x, int y, int button, int clickCount) {
_grid->openTrayAtSelected();
}
#pragma mark - #pragma mark -
GridItemTray::GridItemTray(GuiObject *boss, int x, int y, int w, int h, int entryID, GridWidget *grid) GridItemTray::GridItemTray(GuiObject *boss, int x, int y, int w, int h, int entryID, GridWidget *grid)
@ -335,6 +343,8 @@ GridWidget::GridWidget(GuiObject *boss, int x, int y, int w, int h)
_thumbnailHeight = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Height"); _thumbnailHeight = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Height");
_thumbnailWidth = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Width"); _thumbnailWidth = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Width");
_gridHeaderHeight = kLineHeight;
_gridHeaderWidth = _thumbnailWidth;
_minGridXSpacing = g_gui.xmlEval()->getVar("Globals.Grid.XSpacing"); _minGridXSpacing = g_gui.xmlEval()->getVar("Globals.Grid.XSpacing");
_gridYSpacing = g_gui.xmlEval()->getVar("Globals.Grid.YSpacing"); _gridYSpacing = g_gui.xmlEval()->getVar("Globals.Grid.YSpacing");
@ -366,6 +376,8 @@ GridWidget::GridWidget(GuiObject *boss, const String &name)
_thumbnailHeight = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Height"); _thumbnailHeight = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Height");
_thumbnailWidth = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Width"); _thumbnailWidth = g_gui.xmlEval()->getVar("Globals.GridItemThumbnail.Width");
_gridHeaderHeight = kLineHeight;
_gridHeaderWidth = _thumbnailWidth;
_minGridXSpacing = g_gui.xmlEval()->getVar("Globals.Grid.XSpacing"); _minGridXSpacing = g_gui.xmlEval()->getVar("Globals.Grid.XSpacing");
_gridYSpacing = g_gui.xmlEval()->getVar("Globals.Grid.YSpacing"); _gridYSpacing = g_gui.xmlEval()->getVar("Globals.Grid.YSpacing");
@ -477,10 +489,14 @@ void GridWidget::sortGroups() {
uint groupID = _groupValueIndex[header]; uint groupID = _groupValueIndex[header];
_sortedEntryList.push_back(GridItemInfo(_groupHeaderPrefix + displayedHeader + _groupHeaderSuffix, groupID)); _sortedEntryList.push_back(GridItemInfo(_groupHeaderPrefix + displayedHeader + _groupHeaderSuffix, groupID));
_sortedEntryList.back().rect.setHeight(_gridHeaderHeight);
_sortedEntryList.back().rect.setWidth(_gridHeaderWidth);
if (_groupExpanded[groupID]) { if (_groupExpanded[groupID]) {
for (int *k = _itemsInGroup[groupID].begin(); k != _itemsInGroup[groupID].end(); ++k) { for (int *k = _itemsInGroup[groupID].begin(); k != _itemsInGroup[groupID].end(); ++k) {
_sortedEntryList.push_back(_dataEntryList[*k]); _sortedEntryList.push_back(_dataEntryList[*k]);
_sortedEntryList.back().rect.setHeight(_gridItemHeight);
_sortedEntryList.back().rect.setWidth(_gridItemWidth);
} }
} }
} }
@ -493,7 +509,28 @@ bool GridWidget::calcVisibleEntries() {
int nFirstVisibleItem = 0, nItemsOnScreen = 0; int nFirstVisibleItem = 0, nItemsOnScreen = 0;
nFirstVisibleItem = _itemsPerRow * (_scrollPos / (_gridItemHeight + _gridYSpacing)); // Binary search to find the last element whose y value is less
// than _scrollPos, i.e., the last item of the topmost visible row.
int start = 0;
int end = (int)_sortedEntryList.size() - 1;
int mid;
int ans = -1;
while (start <= end) {
mid = start + (end - start) / 2;
if (_sortedEntryList[mid].rect.top >= _scrollPos) {
end = mid - 1;
} else {
ans = mid;
start = mid + 1;
}
}
nFirstVisibleItem = ans;
// We want the leftmost item from the topmost visible row, so we traverse backwards
while ((nFirstVisibleItem >= 0) &&
(_sortedEntryList[nFirstVisibleItem].rect.top == _sortedEntryList[ans].rect.top)) {
nFirstVisibleItem--;
}
nFirstVisibleItem++;
nFirstVisibleItem = (nFirstVisibleItem < 0) ? 0 : nFirstVisibleItem; nFirstVisibleItem = (nFirstVisibleItem < 0) ? 0 : nFirstVisibleItem;
nItemsOnScreen = (3 + (_scrollWindowHeight / (_gridItemHeight + _gridYSpacing))) * (_itemsPerRow); nItemsOnScreen = (3 + (_scrollWindowHeight / (_gridItemHeight + _gridYSpacing))) * (_itemsPerRow);
@ -503,11 +540,11 @@ bool GridWidget::calcVisibleEntries() {
_itemsOnScreen = nItemsOnScreen; _itemsOnScreen = nItemsOnScreen;
_firstVisibleItem = nFirstVisibleItem; _firstVisibleItem = nFirstVisibleItem;
int toRender = MIN(_firstVisibleItem + _itemsOnScreen, (int)_dataEntryList.size()); int toRender = MIN(_firstVisibleItem + _itemsOnScreen, (int)_sortedEntryList.size());
_visibleEntryList.clear(); _visibleEntryList.clear();
for (int ind = _firstVisibleItem; ind < toRender; ++ind) { for (int ind = _firstVisibleItem; ind < toRender; ++ind) {
GridItemInfo *iter = _dataEntryList.begin() + ind; GridItemInfo *iter = _sortedEntryList.begin() + ind;
_visibleEntryList.push_back(iter); _visibleEntryList.push_back(iter);
} }
} }
@ -593,11 +630,9 @@ void GridWidget::updateGrid() {
} }
void GridWidget::assignEntriesToItems() { void GridWidget::assignEntriesToItems() {
// Assign entries from _visibleEntryList to each GridItem in _gridItems // Assign entries from _visibleEntries to each GridItem in _gridItems
Common::Array<GridItemInfo *>::iterator eit = _visibleEntryList.begin(); Common::Array<GridItemInfo *>::iterator eit = _visibleEntryList.begin();
// Start assigning from the second row as the first row is supposed Common::Array<GridItemWidget *>::iterator it = _gridItems.begin();
// to be offscreen.
Common::Array<GridItemWidget *>::iterator it = _gridItems.begin() + _itemsPerRow;
for (int k = 0; k < _itemsOnScreen; ++k) { for (int k = 0; k < _itemsOnScreen; ++k) {
GridItemWidget *item = *it; GridItemWidget *item = *it;
@ -605,6 +640,8 @@ void GridWidget::assignEntriesToItems() {
if (eit != _visibleEntryList.end()) { if (eit != _visibleEntryList.end()) {
// Assign entry and update // Assign entry and update
item->setActiveEntry(*entry); item->setActiveEntry(*entry);
item->setPos(entry->rect.left, entry->rect.top - _scrollPos);
item->setSize(entry->rect.width(), entry->rect.height());
item->update(); item->update();
if (k >= _itemsOnScreen - _itemsPerRow) if (k >= _itemsOnScreen - _itemsPerRow)
item->setVisible(false); item->setVisible(false);
@ -613,7 +650,9 @@ void GridWidget::assignEntriesToItems() {
++eit; ++eit;
} else { } else {
// If we run out of visible entries to display. // If we run out of visible entries to display.
// e.g., scrolled to the very bottom, we make items invisible. // e.g., scrolled to the very bottom, we make items invisible,
// and move them out of view to keep them from registering mouse events.
item->setPos(_scrollWindowWidth, _scrollWindowHeight);
item->setVisible(false); item->setVisible(false);
} }
@ -638,17 +677,6 @@ void GridWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
reloadThumbnails(); reloadThumbnails();
} }
int row = 0;
int col = 0;
for (Common::Array<GridItemWidget *>::iterator it = _gridItems.begin(); it != _gridItems.end(); ++it) {
(*it)->setPos(2 * _minGridXSpacing + col * (_gridItemWidth + _gridXSpacing),
_gridYSpacing + (row - 1) * (_gridItemHeight + _gridYSpacing) - (_scrollPos % (_gridItemHeight + _gridYSpacing)));
if (++col >= _itemsPerRow) {
++row;
col = 0;
}
}
assignEntriesToItems(); assignEntriesToItems();
markAsDirty(); markAsDirty();
@ -677,6 +705,9 @@ void GridWidget::reflowLayout() {
reloadThumbnails(); reloadThumbnails();
loadFlagIcons(); loadFlagIcons();
} }
_gridHeaderHeight = kLineHeight;
_gridHeaderWidth = _scrollWindowWidth - _scrollBarWidth - 2 * _gridXSpacing;
_minGridXSpacing = g_gui.xmlEval()->getVar("Globals.Grid.XSpacing"); _minGridXSpacing = g_gui.xmlEval()->getVar("Globals.Grid.XSpacing");
_gridYSpacing = g_gui.xmlEval()->getVar("Globals.Grid.YSpacing"); _gridYSpacing = g_gui.xmlEval()->getVar("Globals.Grid.YSpacing");
@ -691,29 +722,57 @@ void GridWidget::reflowLayout() {
_itemsPerRow = MAX(((_scrollWindowWidth - (2 * _minGridXSpacing) - _scrollBarWidth) / (_gridItemWidth + _minGridXSpacing)), 1); _itemsPerRow = MAX(((_scrollWindowWidth - (2 * _minGridXSpacing) - _scrollBarWidth) / (_gridItemWidth + _minGridXSpacing)), 1);
_gridXSpacing = MAX(((_scrollWindowWidth - (2 * _minGridXSpacing) - _scrollBarWidth) - (_itemsPerRow * _gridItemWidth)) / _itemsPerRow, _minGridXSpacing); _gridXSpacing = MAX(((_scrollWindowWidth - (2 * _minGridXSpacing) - _scrollBarWidth) - (_itemsPerRow * _gridItemWidth)) / _itemsPerRow, _minGridXSpacing);
_rows = ceil(_dataEntryList.size() / (float)_itemsPerRow); int row = 0;
int col = 0;
Common::Point p(_gridXSpacing, _gridYSpacing);
_innerHeight = _trayHeight + _gridYSpacing + _rows * (_gridItemHeight + _gridYSpacing); for (int k = 0; k < (int)_sortedEntryList.size(); ++k) {
_innerWidth = (2 * _minGridXSpacing) + (_itemsPerRow * (_gridItemWidth + _gridXSpacing)); if (_sortedEntryList[k].isHeader) {
while (col != 0) {
if (++col >= _itemsPerRow) {
col = 0;
++row;
p.x = _gridXSpacing;
p.y += _sortedEntryList[k - 1].rect.height() + _gridYSpacing;
}
}
_sortedEntryList[k].rect.moveTo(p);
++row;
p.y += _sortedEntryList[k].rect.height() + _gridYSpacing;
} else {
_sortedEntryList[k].rect.moveTo(p);
if (++col >= _itemsPerRow) {
++row;
p.y += _sortedEntryList[k].rect.height() + _gridYSpacing;
col = 0;
p.x = _gridXSpacing;
} else {
p.x += _sortedEntryList[k].rect.width() + _gridXSpacing;
}
}
warning("Titel: %s \tX: %d Y: %d", _sortedEntryList[k].title.c_str(), _sortedEntryList[k].rect.left, _sortedEntryList[k].rect.top);
}
_rows = row;
_innerHeight = p.y + _gridItemHeight + _gridYSpacing + _trayHeight;
_innerWidth = _gridXSpacing + (_itemsPerRow * (_gridItemWidth + _gridXSpacing));
_scrollBar->checkBounds(_scrollBar->_currentPos); _scrollBar->checkBounds(_scrollBar->_currentPos);
_scrollPos = _scrollBar->_currentPos; _scrollPos = _scrollBar->_currentPos;
int row = 0;
int col = 0;
_scrollBar->resize(_scrollWindowWidth - _scrollBarWidth, 0, _scrollBarWidth, _scrollWindowHeight, false); _scrollBar->resize(_scrollWindowWidth - _scrollBarWidth, 0, _scrollBarWidth, _scrollWindowHeight, false);
if (calcVisibleEntries()) { if (calcVisibleEntries()) {
reloadThumbnails(); reloadThumbnails();
} }
row = 0;
col = 0;
for (int k = 0; k < _itemsOnScreen; ++k) { for (int k = 0; k < _itemsOnScreen; ++k) {
GridItemWidget *newItem = new GridItemWidget(this, GridItemWidget *newItem = new GridItemWidget(this);
2 * _minGridXSpacing + col * (_gridItemWidth + _gridXSpacing), newItem->setVisible(false);
_gridYSpacing + (row - 1) * (_gridItemHeight + _gridYSpacing) - (_scrollPos % (_gridItemHeight + _gridYSpacing)),
_gridItemWidth,
_gridItemHeight);
_gridItems.push_back(newItem); _gridItems.push_back(newItem);
@ -733,6 +792,13 @@ void GridWidget::openTray(int x, int y, int entryId) {
_tray->runModal(); _tray->runModal();
} }
void GridWidget::openTrayAtSelected() {
if (_selectedEntry) {
_tray = new GridItemTray(this, _x + _selectedEntry->rect.left - _gridXSpacing / 3, _y + _selectedEntry->rect.bottom - _scrollPos, _gridItemWidth + 2 * (_gridXSpacing / 3), _trayHeight, _selectedEntry->entryID, this);
_tray->runModal();
}
}
void GridWidget::scrollBarRecalc() { void GridWidget::scrollBarRecalc() {
_scrollBar->_numEntries = _innerHeight; _scrollBar->_numEntries = _innerHeight;
_scrollBar->_entriesPerPage = _scrollWindowHeight - _gridYSpacing; _scrollBar->_entriesPerPage = _scrollWindowHeight - _gridYSpacing;

View file

@ -68,6 +68,8 @@ struct GridItemInfo {
Common::Language language; Common::Language language;
Common::Platform platform; Common::Platform platform;
Common::Rect rect;
GridItemInfo(int id, const String &eid, const String &gid GridItemInfo(int id, const String &eid, const String &gid
,const String &t, Common::Language l, Common::Platform p) ,const String &t, Common::Language l, Common::Platform p)
: entryID(id), gameid(gid), engineid(eid), title(t), language(l), platform(p), isHeader(false) { : entryID(id), gameid(gid), engineid(eid), title(t), language(l), platform(p), isHeader(false) {
@ -142,6 +144,8 @@ protected:
public: public:
int _gridItemHeight; int _gridItemHeight;
int _gridItemWidth; int _gridItemWidth;
int _gridHeaderHeight;
int _gridHeaderWidth;
int _gridXSpacing; int _gridXSpacing;
int _gridYSpacing; int _gridYSpacing;
int _trayHeight; int _trayHeight;
@ -189,6 +193,7 @@ public:
void reflowLayout() override; void reflowLayout() override;
void openTray(int x, int y, int entryID); void openTray(int x, int y, int entryID);
void openTrayAtSelected();
void scrollBarRecalc(); void scrollBarRecalc();
}; };
@ -216,6 +221,7 @@ public:
void handleMouseEntered(int button) override; void handleMouseEntered(int button) override;
void handleMouseLeft(int button) override; void handleMouseLeft(int button) override;
void handleMouseDown(int x, int y, int button, int clickCount) override; void handleMouseDown(int x, int y, int button, int clickCount) override;
void handleMouseUp(int x, int y, int button, int clickCount) override;
void handleMouseMoved(int x, int y, int button) override; void handleMouseMoved(int x, int y, int button) override;
}; };