Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/ui/defaulttrackerwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ DefaultTrackerWindow::DefaultTrackerWindow(const char* title, SDL_Surface* icon,
true);
}

_loadPackWidget = new LoadPackWidget(0,0,0,0,_fontStore);
_loadPackWidget = new LoadPackWidget(0,0,0,0,_fontStore, this);
_loadPackWidget->setPosition({0,0});
_loadPackWidget->setSize(_size);
_loadPackWidget->setBackground({0,0,0});
Expand Down Expand Up @@ -362,9 +362,11 @@ void DefaultTrackerWindow::showOpen()
{
_loadPackWidget->update();
_loadPackWidget->setVisible(true);
_loadPackWidget->focusFilter();
}
void DefaultTrackerWindow::hideOpen()
{
_loadPackWidget->releaseFilterFocus();
_loadPackWidget->setVisible(false);
}

Expand Down
157 changes: 137 additions & 20 deletions src/ui/loadpackwidget.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
#include "loadpackwidget.h"
#include "../core/pack.h"
#include "../core/assets.h"
#include "../uilib/hbox.h"
#include "../uilib/vbox.h"
#include "../uilib/scrollvbox.h"
#include "../uilib/label.h"
#include "../uilib/imagebutton.h"
#include "defaults.h" // DEFAULT_FONT_*
#include <SDL2/SDL.h>
#include <cctype>

namespace Ui {

LoadPackWidget::LoadPackWidget(int x, int y, int w, int h, FontStore *fontStore)
: SimpleContainer(x,y,w,h), _fontStore(fontStore)
static std::string urlEncode(const std::string& in)
{
static const char hex[] = "0123456789ABCDEF";
std::string out;
for (unsigned char c : in) {
if (isalnum(c) || c=='-' || c=='_' || c=='.' || c=='~' || c=='/')
out += (char)c;
else {
out += '%';
out += hex[(c>>4)&0xf];
out += hex[c&0xf];
}
}
return out;
}

static void openPackDirectory()
{
for (const auto& searchPath : Pack::getSearchPaths()) {
if (!fs::is_directory(searchPath))
continue;
std::string url = "file://" + urlEncode(searchPath.u8string());
if (SDL_OpenURL(url.c_str()) == 0)
return;
fprintf(stderr, "LoadPackWidget: could not open pack directory '%s'\n", searchPath.u8string().c_str());
}
}

LoadPackWidget::LoadPackWidget(int x, int y, int w, int h, FontStore *fontStore, Window *window)
: SimpleContainer(x,y,w,h), _fontStore(fontStore), _window(window)
{
_font = _fontStore->getFont(DEFAULT_FONT_NAME, DEFAULT_FONT_SIZE);
_smallFont = _fontStore->getFont(DEFAULT_FONT_NAME, DEFAULT_FONT_SIZE - 2);
Expand All @@ -18,6 +50,7 @@ LoadPackWidget::LoadPackWidget(int x, int y, int w, int h, FontStore *fontStore)
onClick += {this, [this](void*, int, int, int button) {
if (button == MouseButton::BUTTON_RIGHT) {
setVisible(false); // TODO: fire onAbort ?
if (_filter) _filter->releaseFocus();
}
}};

Expand All @@ -39,21 +72,115 @@ LoadPackWidget::LoadPackWidget(int x, int y, int w, int h, FontStore *fontStore)
hbox->addChild(variants);
hbox->setSpacing(1);
hbox->setPadding(2);
addChild(hbox);
_main = hbox;

auto filter = new TextField(0,0,0,0, _font, window);
filter->setGrow(1,0);
filter->setPlaceholder("Filter packs...");
filter->setBackground({16,16,16});
_filter = filter;

auto btnClear = new Button(0,0,0,0, _font, "Clear");
btnClear->setGrow(0,0);
btnClear->setMinSize({64, btnClear->getAutoHeight()+4});
_btnClearFilter = btnClear;

btnClear->onClick += {this, [this](void*, int, int, int button) {
if (button == MouseButton::BUTTON_LEFT) {
_filter->clear();
}
}};

auto btnOpenFolder = new ImageButton(0,0,24,0, asset("closed.png"));
btnOpenFolder->setGrow(0,0);
btnOpenFolder->setMinSize({24, 0});
_btnOpenFolder = btnOpenFolder;

btnOpenFolder->onClick += {this, [](void*, int, int, int button) {
if (button == MouseButton::BUTTON_LEFT) {
openPackDirectory();
}
}};

filter->onTextChanged += {this, [this](void*, const std::string&) {
refreshPacks();
}};

auto filterBar = new HBox(0,0,0,0);
filterBar->setGrow(1,0);
filterBar->setPadding(2);
filterBar->setSpacing(4);
filterBar->addChild(filter);
filterBar->addChild(btnClear);
filterBar->addChild(btnOpenFolder);
filterBar->setHeight(filter->getHeight());
_filterBar = filterBar;

auto root = new VBox(0,0,0,0);
root->setGrow(1,1);
root->setPadding(0);
root->setSpacing(1);
root->addChild(filterBar);
root->addChild(hbox);
_root = root;
addChild(root);

_packs->onMouseLeave += {this, [this](void*) {
if (_disableHoverSelect && _curPackHover) {
if (_curPackHover == _curPackLabel) {
_curPackHover->setBackground(PACK_BG_ACTIVE);
} else {
_curPackHover->setBackground(PACK_BG_DEFAULT);
}
}
}};
}

void LoadPackWidget::focusFilter()
{
if (_filter) _filter->grabFocus();
}

void LoadPackWidget::releaseFilterFocus()
{
if (_filter) _filter->releaseFocus();
}

void LoadPackWidget::update()
{
auto availablePacks = Pack::ListAvailable();
_availablePacks = Pack::ListAvailable();
if (_filter) _filter->clear();
refreshPacks();
}

static std::string toLower(const std::string& in)
{
std::string out = in;
for (auto& c : out)
if (c >= 'A' && c <= 'Z') c += 'a'-'A';
return out;
}

void LoadPackWidget::refreshPacks()
{
_packs->clearChildren();
_variants->clearChildren();
_curPackHover = nullptr;
_curPackLabel = nullptr;
_curVariantLabel = nullptr;
_disableHoverSelect = false;

for (auto& pack : availablePacks) {
std::string filter;
if (_filter) filter = toLower(_filter->getText());

int shown = 0;
for (auto& pack : _availablePacks) {
if (!filter.empty()) {
std::string name = toLower(pack.packName + " " + pack.gameName + " " + pack.version);
if (name.find(filter) == std::string::npos)
continue;
}
shown++;
auto lbl = new Label(0, 0, 0, 0, _font, " " + pack.packName + " " + pack.version); // TODO: button instead of label
lbl->setGrow(1,0);
lbl->setTextAlignment(Label::HAlign::LEFT, Label::VAlign::MIDDLE);
Expand Down Expand Up @@ -126,20 +253,11 @@ void LoadPackWidget::update()
}};
}

_packs->onMouseLeave += {this, [this](void*) {
if (_disableHoverSelect && _curPackHover) {
if (_curPackHover == _curPackLabel) {
_curPackHover->setBackground(PACK_BG_ACTIVE);
} else {
_curPackHover->setBackground(PACK_BG_DEFAULT);
}
}
}};

if (availablePacks.empty()) {
auto* lbl = new Label(0, 0, 0, 0, _font,
"No packs installed!\n"
"Drag & drop packs into the window to install them.");
if (shown == 0) {
const char* msg = _availablePacks.empty() ?
"No packs installed!\nDrag & drop packs into the window to install them." :
"No packs found!";
auto* lbl = new Label(0, 0, 0, 0, _font, msg);
lbl->setGrow(1,1);
lbl->setTextAlignment(Label::HAlign::LEFT, Label::VAlign::MIDDLE);
lbl->setMinSize(lbl->getAutoSize());
Expand All @@ -149,7 +267,6 @@ void LoadPackWidget::update()
spacer->setGrow(1,1);
_packs->addChild(spacer);
}
_main->setSize(_size);
_main->relayout(); // TODO: have this be done automatically
}

Expand Down
24 changes: 21 additions & 3 deletions src/ui/loadpackwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,56 @@
#include "../uilib/vbox.h"
#include "../uilib/scrollvbox.h"
#include "../uilib/label.h"
#include "../uilib/button.h"
#include "../uilib/imagebutton.h"
#include "../uilib/textfield.h"
#include "../uilib/fontstore.h"
#include "../core/signal.h"
#include <SDL2/SDL_ttf.h>

#include "../core/fs.h"
#include "../core/pack.h"
#include <vector>

namespace Ui {

class Window;

class LoadPackWidget : public SimpleContainer {
public:
using FONT = FontStore::FONT;
LoadPackWidget(int x, int y, int w, int h, FontStore *fontStore);
LoadPackWidget(int x, int y, int w, int h, FontStore *fontStore, Window *window=nullptr);

void update();
void focusFilter();
void releaseFilterFocus();

Signal<const fs::path&, const std::string&> onPackSelected;

virtual void setSize(Size size) override; // TODO: have more intelligent hbox instead

protected:
FontStore *_fontStore;
FONT _font;
FONT _smallFont;

Window *_window;
VBox *_root = nullptr;
HBox *_filterBar = nullptr;
TextField *_filter = nullptr;
Button *_btnClearFilter = nullptr;
ImageButton *_btnOpenFolder = nullptr;

ScrollVBox *_packs;
VBox *_variants;
HBox *_main;
Label *_curPackLabel = nullptr;
Label *_curVariantLabel = nullptr;
Label *_curPackHover = nullptr;
bool _disableHoverSelect = false;
std::vector<Pack::Info> _availablePacks;

void refreshPacks();

static constexpr Color PACK_BG_DEFAULT = {32, 32, 32};
static constexpr Color PACK_BG_ACTIVE = {32, 128, 32};
Expand All @@ -50,4 +69,3 @@ class LoadPackWidget : public SimpleContainer {
} // namespace Ui

#endif /* _UI_LOADPACKWIDGET_H */

Loading
Loading