From dc10ca9c004cfb3166ab2d0563639e296171816b Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Wed, 24 Nov 2021 23:27:42 +0100 Subject: [PATCH] added icons to file lists and removed special directory name formatting --- Changes.txt | 2 + src/emucore/FSNode.cxx | 6 +- src/gui/FileListWidget.cxx | 256 ++++++++++++++++++++++++++++++++--- src/gui/FileListWidget.hxx | 13 ++ src/gui/LauncherDialog.cxx | 2 +- src/gui/StringListWidget.cxx | 6 +- src/gui/StringListWidget.hxx | 1 + 7 files changed, 257 insertions(+), 29 deletions(-) diff --git a/Changes.txt b/Changes.txt index 7d1368538..18cf0a2dd 100644 --- a/Changes.txt +++ b/Changes.txt @@ -16,6 +16,8 @@ * Added option to toggle autofire mode. + * Added icons to file lists (TODO: doc) + -Have fun! diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index f240ebadc..45f640bc2 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -171,7 +171,7 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, if (includeParentDirectory && hasParent()) { FilesystemNode parent = getParent(); - parent.setName(" [..]"); + parent.setName(".."); fslist.emplace_back(parent); } @@ -204,10 +204,6 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, else #endif { - // Make directories stand out - if(i->isDirectory()) - i->setName(" [" + i->getName() + "]"); - FilesystemNode node(i); if(includeChildDirectories) diff --git a/src/gui/FileListWidget.cxx b/src/gui/FileListWidget.cxx index 5a73f3bcb..781160482 100644 --- a/src/gui/FileListWidget.cxx +++ b/src/gui/FileListWidget.cxx @@ -21,6 +21,8 @@ #include "FileListWidget.hxx" #include "TimerManager.hxx" #include "ProgressDialog.hxx" +#include "FBSurface.hxx" +#include "Bankswitch.hxx" #include "bspf.hxx" @@ -56,9 +58,6 @@ void FileListWidget::setDirectory(const FilesystemNode& node, string name = tmp.getName(); if(name.back() == FilesystemNode::PATH_SEPARATOR) name.pop_back(); - if(!BSPF::startsWithIgnoreCase(name, " [")) - name = " [" + name.append("]"); - _history.push(name); tmp = tmp.getParent(); } @@ -102,16 +101,29 @@ void FileListWidget::setLocation(const FilesystemNode& node, size_t orgLen = _node.getShortPath().length(); _dirList.clear(); + _iconList.clear(); for(const auto& file : _fileList) { const string path = file.getShortPath(); + const string name = file.getName(); - l.push_back(file.getName()); + l.push_back(name); // display only relative path in tooltip if(path.length() >= orgLen) _dirList.push_back(path.substr(orgLen)); else _dirList.push_back(path); + if(file.isDirectory()) + { + if(BSPF::endsWithIgnoreCase(name, ".zip")) + _iconList.push_back(IconType::zip); + else + _iconList.push_back(IconType::directory); + } + else if(file.isFile() && Bankswitch::isValidRomName(name)) + _iconList.push_back(IconType::rom); + else + _iconList.push_back(IconType::unknown); } setList(l); @@ -167,26 +179,21 @@ bool FileListWidget::handleText(char text) // (or a substring accumulated from the last couple key presses). // Only works in a useful fashion if the list entries are sorted. uInt64 time = TimerManager::getTicks() / 1000; + if(_quickSelectTime < time) - { - if(std::isupper(text)) - { - // Select directories when the first character is uppercase - _quickSelectStr = " ["; - _quickSelectStr.push_back(text); - } - else - _quickSelectStr = text; - } + _quickSelectStr = text; else _quickSelectStr += text; _quickSelectTime = time + _QUICK_SELECT_DELAY; int selectedItem = 0; - for(const auto& i: _list) + for(const auto& i : _list) { if(BSPF::startsWithIgnoreCase(i, _quickSelectStr)) - break; + // Select directories when the first character is uppercase + if(std::isupper(_quickSelectStr[0]) == + (_iconList[selectedItem] == IconType::directory)) + break; selectedItem++; } @@ -215,7 +222,7 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int _selected = data; if(selected().isDirectory()) { - if(selected().getName() == " [..]") + if(selected().getName() == "..") selectParent(); else { @@ -246,11 +253,219 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int setTarget(this); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int FileListWidget::drawIcon(int i, int x, int y, ColorId color) +{ + const Icon unknown_small = { + 0b00111111'1100000, + 0b00100000'0110000, + 0b00100000'0011000, + 0b00100000'0001100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00100000'0000100, + 0b00111111'1111100 + }; + const Icon rom_small = { + 0b00001111'1110000, + 0b00001010'1010000, + 0b00001010'1010000, + 0b00001010'1010000, + 0b00001010'1010000, + 0b00001010'1010000, + 0b00011010'1011000, + 0b00110010'1001100, + 0b00100110'1100100, + 0b11101110'1110111, + 0b10001010'1010001, + 0b10011010'1011001, + 0b11110011'1001111 + }; + const Icon directory_small = { + 0b11111000'0000000, + 0b11111100'0000000, + 0b11111111'1111111, + 0b10000000'0000001, + 0b10000000'0000001, + 0b10000000'0000001, + 0b10000000'0000001, + 0b10000000'0000001, + 0b10000000'0000001, + 0b10000000'0000001, + 0b10000000'0000001, + 0b10000000'0000001, + 0b11111111'1111111 + }; + const Icon zip_small = { + //0b0011111'11111111, + //0b0110000'11000111, + //0b1111111'11111101, + //0b1000001'00000111, + //0b1000001'00000101, + //0b1000001'00000111, + //0b1000001'00000111, + //0b1111111'11111101, + //0b1000001'00000111, + //0b1000001'00000101, + //0b1000001'00000111, + //0b1000001'00000110, + //0b1111111'11111100 + 0b11111000'0000000, + 0b11111100'0000000, + 0b11111111'1111111, + 0b10000000'0000001, + 0b10001111'1110001, + 0b10000000'1110001, + 0b10000001'1100001, + 0b10000011'1000001, + 0b10000111'0000001, + 0b10001110'0000001, + 0b10001111'1110001, + 0b10000000'0000001, + 0b11111111'1111111 + + }; + const Icon unknown_large = { + 0b00111'11111111'11000000, + 0b00111'11111111'11100000, + 0b00110'00000000'01110000, + 0b00110'00000000'00111000, + 0b00110'00000000'00011100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00110'00000000'00001100, + 0b00111'11111111'11111100, + 0b00111'11111111'11111100 + }; + const Icon rom_large = { + 0b00000'01111111'11000000, + 0b00000'01111111'11000000, + 0b00000'01101010'11000000, + 0b00000'01101010'11000000, + 0b00000'01101010'11000000, + 0b00000'01101010'11000000, + 0b00000'01101010'11000000, + 0b00000'01101010'11000000, + 0b00000'11101010'11100000, + 0b00000'11001010'01100000, + 0b00000'11001010'01100000, + 0b00001'11001010'01110000, + 0b00001'10001010'00110000, + 0b00011'10011011'00111000, + 0b00011'00011011'00011000, + 0b11111'00111011'10011111, + 0b11110'01111011'11001111, + 0b11000'01111011'11000011, + 0b11000'11111011'11100011, + 0b11111'11011111'01111111, + 0b11111'10011111'00111111 + }; + const Icon directory_large = { + 0b111111'10000000'0000000, + 0b111111'11000000'0000000, + 0b111111'11100000'0000000, + 0b111111'11111111'1111111, + 0b111111'11111111'1111111, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b111111'11111111'1111111, + 0b111111'11111111'1111111 + }; + const Icon zip_large = { + 0b111111'10000000'0000000, + 0b111111'11000000'0000000, + 0b111111'11100000'0000000, + 0b111111'11111111'1111111, + 0b111111'11111111'1111111, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b110000'11111111'1000011, + 0b110000'11111111'1000011, + 0b110000'00000011'0000011, + 0b110000'00000110'0000011, + 0b110000'00001100'0000011, + 0b110000'00011000'0000011, + 0b110000'00110000'0000011, + 0b110000'01100000'0000011, + 0b110000'11111111'1000011, + 0b110000'11111111'1000011, + 0b110000'00000000'0000011, + 0b110000'00000000'0000011, + 0b111111'11111111'1111111, + 0b111111'11111111'1111111 + }; + const bool smallIcon = iconWidth() < 24; + const int iconGap = smallIcon ? 2 : 3; + Icon icon = smallIcon ? unknown_small : unknown_large; + + switch(_iconList[i]) + { + case IconType::rom: + icon = smallIcon ? rom_small: rom_large; + break; + + case IconType::directory: + icon = smallIcon ? directory_small : directory_large; + break; + + case IconType::zip: + icon = smallIcon ? zip_small : zip_large; + break; + + default: + break; + } + + FBSurface& s = _boss->dialog().surface(); + + s.drawBitmap(icon.data(), x + 1 + iconGap, y + (_lineHeight - static_cast(icon.size())) / 2, + color, iconWidth() - iconGap * 2, static_cast(icon.size())); + + return iconWidth(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int FileListWidget::iconWidth() const +{ + bool smallIcon = _lineHeight < 26; + + return smallIcon ? 16 + 4: 24 + 6; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FileListWidget::getToolTip(const Common::Point& pos) const { - Common::Rect rect = getEditRect(); - int idx = getToolTipIndex(pos); + const Common::Rect rect = getEditRect(); + const int idx = getToolTipIndex(pos); if(idx < 0) return EmptyString; @@ -260,12 +475,11 @@ string FileListWidget::getToolTip(const Common::Point& pos) const const string value = _list[idx]; - if(uInt32(_font.getStringWidth(value)) > rect.w()) + if(uInt32(_font.getStringWidth(value)) > rect.w() - iconWidth()) return _toolTipText + value; else return _toolTipText; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 FileListWidget::_QUICK_SELECT_DELAY = 300; diff --git a/src/gui/FileListWidget.hxx b/src/gui/FileListWidget.hxx index c6a964c38..857263ea3 100644 --- a/src/gui/FileListWidget.hxx +++ b/src/gui/FileListWidget.hxx @@ -96,12 +96,24 @@ class FileListWidget : public StringListWidget ProgressDialog& progress(); void incProgress(); + private: + enum class IconType { + unknown, + rom, + directory, + zip + }; + using IconTypeList = std::vector; + using Icon = std::vector; + private: /** Very similar to setDirectory(), but also updates the history */ void setLocation(const FilesystemNode& node, const string& select); bool handleText(char text) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + int drawIcon(int i, int x, int y, ColorId color) override; + int iconWidth() const; private: FilesystemNode::ListMode _fsmode{FilesystemNode::ListMode::All}; @@ -111,6 +123,7 @@ class FileListWidget : public StringListWidget bool _includeSubDirs{false}; StringList _dirList; + IconTypeList _iconList; Common::FixedStack _history; uInt32 _selected{0}; diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index a8976e8a6..422788597 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -796,7 +796,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, case kLoadROMCmd: if(myList->selected().isDirectory()) { - if(myList->selected().getName() == " [..]") + if(myList->selected().getName() == "..") myList->selectParent(); else myList->selectDirectory(); diff --git a/src/gui/StringListWidget.cxx b/src/gui/StringListWidget.cxx index a3fab1622..32696c54e 100644 --- a/src/gui/StringListWidget.cxx +++ b/src/gui/StringListWidget.cxx @@ -102,6 +102,7 @@ void StringListWidget::drawWidget(bool hilite) for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++) { const int y = _y + 2 + _lineHeight * i; + int iw = 0; ColorId textColor = kTextColor; // Draw the selected item inverted, on a highlighted background. @@ -115,17 +116,18 @@ void StringListWidget::drawWidget(bool hilite) else s.frameRect(_x + 1, _y + 1 + _lineHeight * i, _w - 1, _lineHeight, kWidColorHi); } + iw = drawIcon(pos, _x, y - 1, textColor); Common::Rect r(getEditRect()); if (_selectedItem == pos && _editMode) { adjustOffset(); - s.drawString(_font, editString(), _x + r.x(), y, r.w(), textColor, + s.drawString(_font, editString(), _x + iw + r.x(), y, r.w() - iw, textColor, TextAlign::Left, -_editScrollOffset, false); } else - s.drawString(_font, _list[pos], _x + r.x(), y, r.w(), textColor); + s.drawString(_font, _list[pos], _x + iw + r.x(), y, r.w() - iw, textColor); } // Only draw the caret while editing, and if it's in the current viewport diff --git a/src/gui/StringListWidget.hxx b/src/gui/StringListWidget.hxx index 41e556f8c..cd134e934 100644 --- a/src/gui/StringListWidget.hxx +++ b/src/gui/StringListWidget.hxx @@ -44,6 +44,7 @@ class StringListWidget : public ListWidget int getToolTipIndex(const Common::Point& pos) const; void drawWidget(bool hilite) override; + virtual int drawIcon(int i, int x, int y, ColorId color) { return 0; } Common::Rect getEditRect() const override; protected: