diff --git a/gui/launcher.cpp b/gui/launcher.cpp index a9d5161cd8d..58ded8e83e2 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -50,6 +50,7 @@ #include "gui/widgets/list.h" #include "gui/widgets/tab.h" #include "gui/widgets/popup.h" +#include "gui/widgets/grid.h" #include "gui/ThemeEval.h" #include "engines/advancedDetector.h" diff --git a/gui/module.mk b/gui/module.mk index 799c4e7d61a..e2d6a05d616 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -35,6 +35,7 @@ MODULE_OBJS := \ widgets/edittext.o \ widgets/list.o \ widgets/popup.o \ + widgets/grid.o \ widgets/scrollbar.o \ widgets/scrollcontainer.o \ widgets/tab.o diff --git a/gui/widget.cpp b/gui/widget.cpp index e9310d86fbb..b739ba55470 100644 --- a/gui/widget.cpp +++ b/gui/widget.cpp @@ -36,9 +36,6 @@ #include "gui/widgets/popup.h" #include "gui/widgets/scrollcontainer.h" -#include "image/bmp.h" -#include "image/png.h" - namespace GUI { Widget::Widget(GuiObject *boss, int x, int y, int w, int h, const Common::U32String &tooltip) @@ -1010,357 +1007,6 @@ void ContainerWidget::drawWidget() { g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), _backgroundType); } -#pragma mark - - -GridItemWidget::GridItemWidget(GridWidget *boss, int x, int y, int w, int h) : -ContainerWidget(boss, x, y, w, h) { - _plat = new GraphicsWidget(this, kThumbnailWidth - 32, kThumbnailHeight - 32, 32, 32); - _lang = new StaticTextWidget(this, kThumbnailWidth - 32, 0, 32, 32, Common::U32String("XX"), Graphics::TextAlign::kTextAlignRight); - _title = new StaticTextWidget(this, 0, kThumbnailHeight, w , kLineHeight*2, Common::U32String("Title"), Graphics::TextAlign::kTextAlignLeft); - _thumb = new GraphicsWidget(this, 0, 0 , kThumbnailWidth, kThumbnailHeight); - _activeEntry = nullptr; - _grid = boss; -} -GridItemWidget::GridItemWidget(GridWidget *boss, GraphicsWidget *th, GraphicsWidget *p, StaticTextWidget *l, StaticTextWidget *t) : - ContainerWidget(boss, 0, 0, 0, 0), _thumb(th), _plat(p), _lang(l), _title(t) { - _activeEntry = nullptr; - _grid = boss; - } - -void GridItemWidget::attachEntry(Common::String key, Common::String description, Common::ConfigManager::Domain *domain) { - Common::String gameid = domain->getVal("gameid"); - Common::String engineid = domain->getVal("engineid"); - Common::String language = "XX"; - Common::String platform = "UNK"; - domain->tryGetVal("language",language); - domain->tryGetVal("platform", platform); - _attachedEntries.push_back(GridItemInfo(gameid, engineid, description, language, platform)); -} - -void GridItemWidget::attachEntry(GridItemInfo &entry) { - _attachedEntries.push_back(entry); -} - -void GridItemWidget::attachEntries(Common::Array entries) { - _attachedEntries.push_back(entries); -} - -void GridItemWidget::setActiveEntry(GridItemInfo &entry) { - _activeEntry = &entry; -} - -void GridItemWidget::updateThumb() { - const Graphics::ManagedSurface *gfx = _grid->filenameToSurface(_activeEntry->thumbPath); - _thumb->setGfx(gfx); -} - -void GridItemWidget::update() { - if ((!_activeEntry) && (!_attachedEntries.empty())) { - _activeEntry = _attachedEntries.begin(); - } - - updateThumb(); - - _lang->setLabel(_activeEntry->language); - _title->setLabel(_activeEntry->title); - - const Graphics::ManagedSurface *gfx; - - if (_activeEntry->platform == "pc") - gfx = _grid->platformToSurface(kPlatformDOS); - else if (_activeEntry->platform == "amiga") - gfx = _grid->platformToSurface(kPlatformAmiga); - else if (_activeEntry->platform == "apple2") - gfx = _grid->platformToSurface(kPlatformApple2); - else - gfx = _grid->platformToSurface(kPlatformUnknown); - - _plat->setGfx(gfx); - - markAsDirty(); -} - -void GridItemWidget::drawWidget() { - g_gui.theme()->drawWidgetBackground(Common::Rect(_x,_y,_x+kThumbnailWidth,_y+kThumbnailHeight), ThemeEngine::WidgetBackground::kThumbnailBackground); -} - -#pragma mark - - -Graphics::ManagedSurface *loadSurfaceFromFile(Common::String &name) { - Graphics::ManagedSurface *surf = nullptr; - const Graphics::Surface *srcSurface = nullptr; - if (name.hasSuffix(".png")) { -#ifdef USE_PNG - Image::PNGDecoder decoder; - Common::FSNode fileNode(name); - Common::SeekableReadStream * stream = fileNode.createReadStream(); - if (stream) { - if (!decoder.loadStream(*stream)) - warning("Error decoding PNG"); - - srcSurface = decoder.getSurface(); - delete stream; - if (!srcSurface) { - warning("Failed to load surface : %s", name.c_str()); - } - if (srcSurface && srcSurface->format.bytesPerPixel != 1) { - surf = new Graphics::ManagedSurface(srcSurface->convertTo(g_system->getOverlayFormat())); - } - - } else { - warning("No such file : %s", name.c_str()); - } -#else - error("No PNG support compiled"); -#endif - } - else { - - } - return surf; -} - -#pragma mark - - -GridWidget::GridWidget(GuiObject *boss, int x, int y, int w, int h) : - ContainerWidget(boss, x, y, w, h) { - loadPlatformIcons(); -} - -GridWidget::GridWidget(GuiObject *boss, const Common::String &name) : - ContainerWidget(boss, name) { - loadPlatformIcons(); - _gridItemHeight = kThumbnailHeight + (2*kLineHeight); - _gridItemWidth = kThumbnailWidth; - _scrollBar = new ScrollBarWidget(this, 0, 0, 20, 100); - _scrollBar->setTarget(this); - _scrollPos = 0; -} - -void GridWidget::setEntryList(Common::Array *list) { - for (auto entryIter = list->begin(); entryIter != list->end(); ++entryIter) { - _allEntries.push_back(*entryIter); - } -} - -void GridWidget::destroyItems() { - for (Common::Array::iterator i = _gridItems.begin(), end = _gridItems.end(); i != end; ++i) { - removeWidget((*i)); - delete (*i); - } - - _gridItems.clear(); -} - -void GridWidget::loadPlatformIcons() { - for (auto iter = _platformIcons.begin(); iter != _platformIcons.end(); ++iter) { - delete *iter; - } - _platformIcons.clear(); - Common::String pathPrefix("./icons/"); - Common::Array iconFilenames; - iconFilenames.push_back(Common::String("dos.png")); - iconFilenames.push_back(Common::String("amiga.png")); - iconFilenames.push_back(Common::String("apple2.png")); - - for (auto i = iconFilenames.begin(); i != iconFilenames.end(); ++i) { - Common::String fullPath = pathPrefix + (*i); - Graphics::ManagedSurface *gfx = loadSurfaceFromFile(fullPath); - if (gfx) { - const Graphics::ManagedSurface *scGfx = scaleGfx(gfx, 32, 32); - _platformIcons.push_back(scGfx); - gfx->free(); - delete gfx; - } - } -} - -bool GridWidget::calcVisibleEntries() { - bool needsReload = false; - - int nFirstVisibleItem = 0; - int nItemsOnScreen = 0; - - nFirstVisibleItem = _itemsPerRow * (-_scrollPos / (_gridItemHeight + kGridItemVPadding)); - nItemsOnScreen = (3 + (_scrollWindowHeight / (_gridItemHeight + kGridItemVPadding))) * (_itemsPerRow); - - if ((nFirstVisibleItem != _firstVisibleItem) || (nItemsOnScreen != _itemsOnScreen)) { - needsReload = true; - _firstVisibleItem = nFirstVisibleItem; - _itemsOnScreen = nItemsOnScreen; - - int toRender = MIN(_firstVisibleItem + _itemsOnScreen, (int)_allEntries.size()-1); - - _visibleEntries.clear(); - for (int ind = _firstVisibleItem; ind < toRender; ++ind) { - GridItemInfo *iter = _allEntries.begin() + ind; - _visibleEntries.push_back(*iter); - } - } - - return needsReload; -} - -void GridWidget::reloadThumbnails() { - Graphics::ManagedSurface *surf = nullptr; - Common::String gameid; - Common::String engineid; - Common::String path; - for (Common::Array::iterator iter = _visibleEntries.begin(); iter != _visibleEntries.end(); ++iter) { - path = Common::String("./icons/")+iter->thumbPath; - if (_loadedSurfaces.contains(path)) { - // warning("Thumbnail already loaded, skipping..."); - } - else { - surf = loadSurfaceFromFile(path); - if (surf) { - const Graphics::ManagedSurface *scSurf(scaleGfx(surf, kThumbnailWidth, 512)); - _loadedSurfaces[path] = scSurf; - } - } - } -} - -const Graphics::ManagedSurface *GridWidget::filenameToSurface(Common::String &name) { - Common::String path = Common::String("./icons/")+name; - - for (auto l = _visibleEntries.begin(); l!=_visibleEntries.end(); ++l) { - if (l->thumbPath == name) { - return _loadedSurfaces[path]; - } - } - - return nullptr; -} - -const Graphics::ManagedSurface *GridWidget::platformToSurface(Platform platformCode) { - if ((platformCode == kPlatformUnknown) || (platformCode < 0 || platformCode >= _platformIcons.size())) { - warning("Unknown Platform"); - return nullptr; - } - return _platformIcons[platformCode]; -} - -void GridWidget::handleMouseWheel(int x, int y, int direction) { - int scrollSpeed = -direction*40; - _scrollPos += scrollSpeed; - if (_scrollPos > 0) { - _scrollPos = 0; - scrollSpeed = 0; - } - if (_scrollPos < -(_innerHeight - _scrollWindowHeight)) { - _scrollPos = -(_innerHeight - _scrollWindowHeight); - scrollSpeed = 0; - } - - bool needsReload = calcVisibleEntries(); - - if (needsReload) { - reloadThumbnails(); - } - - // warning("%d %d", _visibleEntries.size(), _gridItems.size()); - Common::Array::iterator eIter = _visibleEntries.begin(); - Common::Array::iterator iter = _gridItems.begin() + (_firstVisibleItem % _gridItems.size()); - - for (int k = 0; k < _gridItems.size(); ++k) { - GridItemWidget *it = *iter; - it->setPos(it->getRelX(), scrollSpeed + it->getRelY()); - - if (it->getRelY() <= -_gridItemHeight) { - it->setVisible(false); - if (it->getRelY() <= -((_gridItemHeight) * 2)) { - it->setPos(it->getRelX(), it->getRelY() + ((_itemsOnScreen / _itemsPerRow) * (kThumbnailHeight + 80))); - } - } - else if (it->getRelY() >= _h) { - it->setVisible(false); - if (it->getRelY() >= -_gridItemHeight + ((_itemsOnScreen / _itemsPerRow) * (kThumbnailHeight + 80))) { - it->setPos(it->getRelX(), it->getRelY() - ((_itemsOnScreen / _itemsPerRow) * (kThumbnailHeight + 80))); - } - } - else { - it->setVisible(true); - } - - if (eIter != _visibleEntries.end()) { - it->setActiveEntry(*eIter); - eIter++; - } - else { - it->setActiveEntry(*_visibleEntries.begin()); - it->setVisible(false); - } - iter++; - if (iter == _gridItems.end()) - iter = _gridItems.begin(); - } - - if (needsReload) { - updateGrid(); - } - - markAsDirty(); -} - -void GridWidget::reflowLayout() { - Widget::reflowLayout(); - destroyItems(); - _scrollWindowHeight = _h; - _scrollWindowWidth = _w; - _itemsPerRow = MAX((((int)_scrollWindowWidth - 100) / kThumbnailWidth) - 1, 1); - - int rows = _allEntries.size() / _itemsPerRow; // change this to be calced using eindow sizes - - _innerHeight = 100 + ((rows + 1) * (kThumbnailHeight + 80)); - _innerWidth = 100 + (_itemsPerRow * (kThumbnailWidth + 50)); - - if (_scrollPos < -(_innerHeight - _scrollWindowHeight)) - _scrollPos = -(_innerHeight - _scrollWindowHeight); - - int row = 0; - int col = 0; - - if (calcVisibleEntries()) { - reloadThumbnails(); - } - - for (Common::Array::iterator i = _visibleEntries.begin(); i != _visibleEntries.end(); ++i) { - - GridItemWidget *newEntry = nullptr; - if (!newEntry) { - newEntry = new GridItemWidget(this, - 50 + col * (kThumbnailWidth + 50), - _scrollPos + 50 + row * (kThumbnailHeight + 80), - kThumbnailWidth, - kThumbnailHeight+kLineHeight*2); - _gridItems.push_back(newEntry); - - if ((newEntry->getRelY() <= -_gridItemHeight) || (newEntry->getRelY() >= _h)) { - newEntry->setVisible(false); - } - else { - newEntry->setVisible(true); - } - - if (++col >= _itemsPerRow) { - ++row; - col = 0; - } - } - newEntry->attachEntry(*i); - newEntry->update(); - } - markAsDirty(); -} - -void GridWidget::updateGrid() { - for (auto i = _gridItems.begin(); i != _gridItems.end(); ++i) { - (*i)->update(); - } -} - - #pragma mark - OptionsContainerWidget::OptionsContainerWidget(GuiObject *boss, const Common::String &name, const Common::String &dialogLayout, diff --git a/gui/widget.h b/gui/widget.h index b3e0df16f4a..d311aefe5e3 100644 --- a/gui/widget.h +++ b/gui/widget.h @@ -461,119 +461,6 @@ protected: ThemeEngine::WidgetBackground _backgroundType; }; -enum Platform { - kPlatformDOS, - kPlatformAmiga, - kPlatformApple2, - kPlatformUnknown = -1 -}; - -struct GridItemInfo -{ - Common::String engineid; - Common::String gameid; - Common::String language; - Common::String title; - Common::String platform; - Common::String thumbPath; - - GridItemInfo(Common::String &eid, Common::String &gid, Common::String &t, Common::String &l, Common::String &p) : - gameid(gid), engineid(eid), title(t), language(l), platform(p) { - thumbPath = Common::String::format("%s-%s.png", engineid.c_str(), gameid.c_str()); - } -}; - - -class GridItemWidget; - -/* GridWidget */ -class GridWidget : public ContainerWidget { -private: - Common::Array _platformIcons; - // _gridItems should be reserved to hold few more than visible items - // Fixing it to 30 for now, 6 items * (4 rows + 1 extra row); - Common::Array _gridItems; - Common::Array _allEntries; - Common::Array _visibleEntries; - Common::HashMap _loadedSurfaces; - - Common::Array> _grid; - - ScrollBarWidget *_scrollBar; - - uint16 _scrollWindowHeight, _scrollWindowWidth, _scrollSpeed; - uint16 _innerHeight, _innerWidth; - uint16 _thumbnailHeight, _thumbnailWidth; - uint16 _gridItemHeight, _gridItemWidth; - - int _scrollPos; - int _itemsPerRow; - int _firstVisibleItem; - int _itemsOnScreen; - - bool _titlesVisible; - - -public: - - GridWidget(GuiObject *boss, int x, int y, int w, int h); - GridWidget(GuiObject *boss, const Common::String &name); - - const Graphics::ManagedSurface * filenameToSurface(Common::String &name); - const Graphics::ManagedSurface * platformToSurface(Platform platformCode); - - - bool calcVisibleEntries(void); - void setEntryList(Common::Array *list); - void destroyItems(); - void loadPlatformIcons(); - void updateGrid(void); - void gridFromGameList(); - int getLoadedNumber(void) {return _loadedSurfaces.size();} - void reloadThumbnails(); - void handleMouseWheel(int x, int y, int direction) override; - void reflowLayout() override; - - - int selectedEntry; -}; - -enum { - kGridItemHPadding = 50, - kGridItemVPadding = 50, - kThumbnailWidth = 192, - kThumbnailHeight = 192 -}; - -/* EntryContainerWidget */ -class GridItemWidget : public ContainerWidget { -public: - GraphicsWidget *_thumb; - GraphicsWidget *_plat; - StaticTextWidget *_lang; - StaticTextWidget *_title; - GridWidget *_grid; - - Common::Array _attachedEntries; - GridItemInfo *_activeEntry; - - bool isHighlighted; - void setActiveEntry(GridItemInfo &entry); - -public: - GridItemWidget(GridWidget *boss, int x, int y, int w, int h); - GridItemWidget(GridWidget *boss, GraphicsWidget *th, GraphicsWidget *p, StaticTextWidget *l, StaticTextWidget *t); - - void attachEntry(Common::String key, Common::String description, Common::ConfigManager::Domain *domain); - void attachEntry(GridItemInfo &entry); - void attachEntries(Common::Array entry); - void setActiveEntry(int i) {setActiveEntry(_attachedEntries[i]);}; - void update(); - void updateThumb(); - void drawWidget() override; - -}; - /* OptionsContainerWidget */ class OptionsContainerWidget : public Widget { public: diff --git a/gui/widgets/grid.cpp b/gui/widgets/grid.cpp new file mode 100644 index 00000000000..e4c9c3e6f91 --- /dev/null +++ b/gui/widgets/grid.cpp @@ -0,0 +1,377 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/system.h" +#include "gui/gui-manager.h" +#include "gui/widgets/grid.h" + +#include "gui/ThemeEval.h" + +namespace GUI { + +GridItemWidget::GridItemWidget(GridWidget *boss, int x, int y, int w, int h) : +ContainerWidget(boss, x, y, w, h) { + _plat = new GraphicsWidget(this, kThumbnailWidth - 32, kThumbnailHeight - 32, 32, 32); + _lang = new StaticTextWidget(this, kThumbnailWidth - 32, 0, 32, 32, Common::U32String("XX"), Graphics::TextAlign::kTextAlignRight); + _title = new StaticTextWidget(this, 0, kThumbnailHeight, w , kLineHeight*2, Common::U32String("Title"), Graphics::TextAlign::kTextAlignLeft); + _thumb = new GraphicsWidget(this, 0, 0 , kThumbnailWidth, kThumbnailHeight); + _activeEntry = nullptr; + _grid = boss; +} +GridItemWidget::GridItemWidget(GridWidget *boss, GraphicsWidget *th, GraphicsWidget *p, StaticTextWidget *l, StaticTextWidget *t) : + ContainerWidget(boss, 0, 0, 0, 0), _thumb(th), _plat(p), _lang(l), _title(t) { + _activeEntry = nullptr; + _grid = boss; + } + +void GridItemWidget::attachEntry(Common::String key, Common::String description, Common::ConfigManager::Domain *domain) { + Common::String gameid = domain->getVal("gameid"); + Common::String engineid = domain->getVal("engineid"); + Common::String language = "XX"; + Common::String platform = "UNK"; + domain->tryGetVal("language",language); + domain->tryGetVal("platform", platform); + _attachedEntries.push_back(GridItemInfo(gameid, engineid, description, language, platform)); +} + +void GridItemWidget::attachEntry(GridItemInfo &entry) { + _attachedEntries.push_back(entry); +} + +void GridItemWidget::attachEntries(Common::Array entries) { + _attachedEntries.push_back(entries); +} + +void GridItemWidget::setActiveEntry(GridItemInfo &entry) { + _activeEntry = &entry; +} + +void GridItemWidget::updateThumb() { + const Graphics::ManagedSurface *gfx = _grid->filenameToSurface(_activeEntry->thumbPath); + _thumb->setGfx(gfx); +} + +void GridItemWidget::update() { + if ((!_activeEntry) && (!_attachedEntries.empty())) { + _activeEntry = _attachedEntries.begin(); + } + + updateThumb(); + + _lang->setLabel(_activeEntry->language); + _title->setLabel(_activeEntry->title); + + const Graphics::ManagedSurface *gfx; + + if (_activeEntry->platform == "pc") + gfx = _grid->platformToSurface(kPlatformDOS); + else if (_activeEntry->platform == "amiga") + gfx = _grid->platformToSurface(kPlatformAmiga); + else if (_activeEntry->platform == "apple2") + gfx = _grid->platformToSurface(kPlatformApple2); + else + gfx = _grid->platformToSurface(kPlatformUnknown); + + _plat->setGfx(gfx); + + markAsDirty(); +} + +void GridItemWidget::drawWidget() { + g_gui.theme()->drawWidgetBackground(Common::Rect(_x,_y,_x+kThumbnailWidth,_y+kThumbnailHeight), ThemeEngine::WidgetBackground::kThumbnailBackground); +} + +#pragma mark - + +Graphics::ManagedSurface *loadSurfaceFromFile(Common::String &name) { + Graphics::ManagedSurface *surf = nullptr; + const Graphics::Surface *srcSurface = nullptr; + if (name.hasSuffix(".png")) { +#ifdef USE_PNG + Image::PNGDecoder decoder; + Common::FSNode fileNode(name); + Common::SeekableReadStream * stream = fileNode.createReadStream(); + if (stream) { + if (!decoder.loadStream(*stream)) + warning("Error decoding PNG"); + + srcSurface = decoder.getSurface(); + delete stream; + if (!srcSurface) { + warning("Failed to load surface : %s", name.c_str()); + } + if (srcSurface && srcSurface->format.bytesPerPixel != 1) { + surf = new Graphics::ManagedSurface(srcSurface->convertTo(g_system->getOverlayFormat())); + } + + } else { + warning("No such file : %s", name.c_str()); + } +#else + error("No PNG support compiled"); +#endif + } + else { + + } + return surf; +} + +#pragma mark - + +GridWidget::GridWidget(GuiObject *boss, int x, int y, int w, int h) : + ContainerWidget(boss, x, y, w, h) { + loadPlatformIcons(); +} + +GridWidget::GridWidget(GuiObject *boss, const Common::String &name) : + ContainerWidget(boss, name) { + loadPlatformIcons(); + _gridItemHeight = kThumbnailHeight + (2*kLineHeight); + _gridItemWidth = kThumbnailWidth; + _scrollPos = 0; +} + +void GridWidget::setEntryList(Common::Array *list) { + for (auto entryIter = list->begin(); entryIter != list->end(); ++entryIter) { + _allEntries.push_back(*entryIter); + } +} + +void GridWidget::destroyItems() { + for (Common::Array::iterator i = _gridItems.begin(), end = _gridItems.end(); i != end; ++i) { + removeWidget((*i)); + delete (*i); + } + + _gridItems.clear(); +} + +void GridWidget::loadPlatformIcons() { + for (auto iter = _platformIcons.begin(); iter != _platformIcons.end(); ++iter) { + delete *iter; + } + _platformIcons.clear(); + Common::String pathPrefix("./icons/"); + Common::Array iconFilenames; + iconFilenames.push_back(Common::String("dos.png")); + iconFilenames.push_back(Common::String("amiga.png")); + iconFilenames.push_back(Common::String("apple2.png")); + + for (auto i = iconFilenames.begin(); i != iconFilenames.end(); ++i) { + Common::String fullPath = pathPrefix + (*i); + Graphics::ManagedSurface *gfx = loadSurfaceFromFile(fullPath); + if (gfx) { + const Graphics::ManagedSurface *scGfx = scaleGfx(gfx, 32, 32); + _platformIcons.push_back(scGfx); + gfx->free(); + delete gfx; + } + } +} + +bool GridWidget::calcVisibleEntries() { + bool needsReload = false; + + int nFirstVisibleItem = 0; + int nItemsOnScreen = 0; + + nFirstVisibleItem = _itemsPerRow * (-_scrollPos / (_gridItemHeight + kGridItemVPadding)); + nItemsOnScreen = (3 + (_scrollWindowHeight / (_gridItemHeight + kGridItemVPadding))) * (_itemsPerRow); + + if ((nFirstVisibleItem != _firstVisibleItem) || (nItemsOnScreen != _itemsOnScreen)) { + needsReload = true; + _firstVisibleItem = nFirstVisibleItem; + _itemsOnScreen = nItemsOnScreen; + + int toRender = MIN(_firstVisibleItem + _itemsOnScreen, (int)_allEntries.size()-1); + + _visibleEntries.clear(); + for (int ind = _firstVisibleItem; ind < toRender; ++ind) { + GridItemInfo *iter = _allEntries.begin() + ind; + _visibleEntries.push_back(*iter); + } + } + + return needsReload; +} + +void GridWidget::reloadThumbnails() { + Graphics::ManagedSurface *surf = nullptr; + Common::String gameid; + Common::String engineid; + Common::String path; + for (Common::Array::iterator iter = _visibleEntries.begin(); iter != _visibleEntries.end(); ++iter) { + path = Common::String("./icons/")+iter->thumbPath; + if (_loadedSurfaces.contains(path)) { + // warning("Thumbnail already loaded, skipping..."); + } + else { + surf = loadSurfaceFromFile(path); + if (surf) { + const Graphics::ManagedSurface *scSurf(scaleGfx(surf, kThumbnailWidth, 512)); + _loadedSurfaces[path] = scSurf; + } + } + } +} + +const Graphics::ManagedSurface *GridWidget::filenameToSurface(Common::String &name) { + Common::String path = Common::String("./icons/")+name; + + for (auto l = _visibleEntries.begin(); l!=_visibleEntries.end(); ++l) { + if (l->thumbPath == name) { + return _loadedSurfaces[path]; + } + } + + return nullptr; +} + +const Graphics::ManagedSurface *GridWidget::platformToSurface(Platform platformCode) { + if ((platformCode == kPlatformUnknown) || (platformCode < 0 || platformCode >= _platformIcons.size())) { + warning("Unknown Platform"); + return nullptr; + } + return _platformIcons[platformCode]; +} + +void GridWidget::handleMouseWheel(int x, int y, int direction) { + int scrollSpeed = -direction*40; + _scrollPos += scrollSpeed; + if (_scrollPos > 0) { + _scrollPos = 0; + scrollSpeed = 0; + } + if (_scrollPos < -(_innerHeight - _scrollWindowHeight)) { + _scrollPos = -(_innerHeight - _scrollWindowHeight); + scrollSpeed = 0; + } + + bool needsReload = calcVisibleEntries(); + + if (needsReload) { + reloadThumbnails(); + } + + // warning("%d %d", _visibleEntries.size(), _gridItems.size()); + Common::Array::iterator eIter = _visibleEntries.begin(); + Common::Array::iterator iter = _gridItems.begin() + (_firstVisibleItem % _gridItems.size()); + + for (int k = 0; k < _gridItems.size(); ++k) { + GridItemWidget *it = *iter; + it->setPos(it->getRelX(), scrollSpeed + it->getRelY()); + + if (it->getRelY() <= -_gridItemHeight) { + it->setVisible(false); + if (it->getRelY() <= -((_gridItemHeight) * 2)) { + it->setPos(it->getRelX(), it->getRelY() + ((_itemsOnScreen / _itemsPerRow) * (kThumbnailHeight + 80))); + } + } + else if (it->getRelY() >= _h) { + it->setVisible(false); + if (it->getRelY() >= -_gridItemHeight + ((_itemsOnScreen / _itemsPerRow) * (kThumbnailHeight + 80))) { + it->setPos(it->getRelX(), it->getRelY() - ((_itemsOnScreen / _itemsPerRow) * (kThumbnailHeight + 80))); + } + } + else { + it->setVisible(true); + } + + if (eIter != _visibleEntries.end()) { + it->setActiveEntry(*eIter); + eIter++; + } + else { + it->setActiveEntry(*_visibleEntries.begin()); + it->setVisible(false); + } + iter++; + if (iter == _gridItems.end()) + iter = _gridItems.begin(); + } + + if (needsReload) { + updateGrid(); + } + + markAsDirty(); +} + +void GridWidget::reflowLayout() { + Widget::reflowLayout(); + destroyItems(); + _scrollWindowHeight = _h; + _scrollWindowWidth = _w; + _itemsPerRow = MAX((((int)_scrollWindowWidth - 100) / kThumbnailWidth) - 1, 1); + + int rows = _allEntries.size() / _itemsPerRow; // change this to be calced using eindow sizes + + _innerHeight = 100 + ((rows + 1) * (kThumbnailHeight + 80)); + _innerWidth = 100 + (_itemsPerRow * (kThumbnailWidth + 50)); + + if (_scrollPos < -(_innerHeight - _scrollWindowHeight)) + _scrollPos = -(_innerHeight - _scrollWindowHeight); + + int row = 0; + int col = 0; + + if (calcVisibleEntries()) { + reloadThumbnails(); + } + + for (Common::Array::iterator i = _visibleEntries.begin(); i != _visibleEntries.end(); ++i) { + + GridItemWidget *newEntry = nullptr; + if (!newEntry) { + newEntry = new GridItemWidget(this, + 50 + col * (kThumbnailWidth + 50), + _scrollPos + 50 + row * (kThumbnailHeight + 80), + kThumbnailWidth, + kThumbnailHeight+kLineHeight*2); + _gridItems.push_back(newEntry); + + if ((newEntry->getRelY() <= -_gridItemHeight) || (newEntry->getRelY() >= _h)) { + newEntry->setVisible(false); + } + else { + newEntry->setVisible(true); + } + + if (++col >= _itemsPerRow) { + ++row; + col = 0; + } + } + newEntry->attachEntry(*i); + newEntry->update(); + } + markAsDirty(); +} + +void GridWidget::updateGrid() { + for (auto i = _gridItems.begin(); i != _gridItems.end(); ++i) { + (*i)->update(); + } +} + +} // End of namespace GUI diff --git a/gui/widgets/grid.h b/gui/widgets/grid.h new file mode 100644 index 00000000000..fe6e5da0995 --- /dev/null +++ b/gui/widgets/grid.h @@ -0,0 +1,150 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef GUI_WIDGETS_GRID_H +#define GUI_WIDGETS_GRID_H + +#include "gui/dialog.h" +#include "gui/widget.h" +#include "common/str.h" +#include "common/array.h" +#include "image/bmp.h" +#include "image/png.h" + +namespace GUI { + +const Graphics::ManagedSurface *scaleGfx(Graphics::ManagedSurface *gfx, int w, int h); + +enum Platform { + kPlatformDOS, + kPlatformAmiga, + kPlatformApple2, + kPlatformUnknown = -1 +}; + +struct GridItemInfo +{ + Common::String engineid; + Common::String gameid; + Common::String language; + Common::String title; + Common::String platform; + Common::String thumbPath; + + GridItemInfo(Common::String &eid, Common::String &gid, Common::String &t, Common::String &l, Common::String &p) : + gameid(gid), engineid(eid), title(t), language(l), platform(p) { + thumbPath = Common::String::format("%s-%s.png", engineid.c_str(), gameid.c_str()); + } +}; + +class GridItemWidget; + +/* GridWidget */ +class GridWidget : public ContainerWidget { +private: + Common::Array _platformIcons; + // _gridItems should be reserved to hold few more than visible items + Common::Array _gridItems; + Common::Array _allEntries; + Common::Array _visibleEntries; + Common::HashMap _loadedSurfaces; + + Common::Array> _grid; + + ScrollBarWidget *_scrollBar; + + uint16 _scrollWindowHeight, _scrollWindowWidth, _scrollSpeed; + uint16 _innerHeight, _innerWidth; + uint16 _thumbnailHeight, _thumbnailWidth; + uint16 _gridItemHeight, _gridItemWidth; + + int _scrollPos; + int _itemsPerRow; + int _firstVisibleItem; + int _itemsOnScreen; + + bool _titlesVisible; + + +public: + + GridWidget(GuiObject *boss, int x, int y, int w, int h); + GridWidget(GuiObject *boss, const Common::String &name); + + const Graphics::ManagedSurface * filenameToSurface(Common::String &name); + const Graphics::ManagedSurface * platformToSurface(Platform platformCode); + + + bool calcVisibleEntries(void); + void setEntryList(Common::Array *list); + void destroyItems(); + void loadPlatformIcons(); + void updateGrid(void); + void gridFromGameList(); + int getLoadedNumber(void) {return _loadedSurfaces.size();} + void reloadThumbnails(); + void handleMouseWheel(int x, int y, int direction) override; + void reflowLayout() override; + + + int selectedEntry; +}; + +enum { + kGridItemHPadding = 50, + kGridItemVPadding = 50, + kThumbnailWidth = 192, + kThumbnailHeight = 192 +}; + +/* EntryContainerWidget */ +class GridItemWidget : public ContainerWidget { +public: + GraphicsWidget *_thumb; + GraphicsWidget *_plat; + StaticTextWidget *_lang; + StaticTextWidget *_title; + GridWidget *_grid; + + Common::Array _attachedEntries; + GridItemInfo *_activeEntry; + + bool isHighlighted; + void setActiveEntry(GridItemInfo &entry); + +public: + GridItemWidget(GridWidget *boss, int x, int y, int w, int h); + GridItemWidget(GridWidget *boss, GraphicsWidget *th, GraphicsWidget *p, StaticTextWidget *l, StaticTextWidget *t); + + void attachEntry(Common::String key, Common::String description, Common::ConfigManager::Domain *domain); + void attachEntry(GridItemInfo &entry); + void attachEntries(Common::Array entry); + void setActiveEntry(int i) {setActiveEntry(_attachedEntries[i]);}; + void update(); + void updateThumb(); + void drawWidget() override; + +}; + +} // End of namespace GUI + +#endif