Browse Source

Add search functionality to ModuleBrowser

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
55ad83d890
3 changed files with 73 additions and 24 deletions
  1. +2
    -2
      include/string.hpp
  2. +63
    -16
      src/app/ModuleBrowser.cpp
  3. +8
    -6
      src/string.cpp

+ 2
- 2
include/string.hpp View File

@@ -15,9 +15,9 @@ Remember that "%s" must reference a `char *`, so use `.c_str()` for `std::string
*/ */
std::string f(const char *format, ...); std::string f(const char *format, ...);
/** Replaces all characters to lowercase letters */ /** Replaces all characters to lowercase letters */
std::string lowercase(std::string s);
std::string lowercase(const std::string &s);
/** Replaces all characters to uppercase letters */ /** Replaces all characters to uppercase letters */
std::string uppercase(std::string s);
std::string uppercase(const std::string &s);
/** Truncates and adds "..." to a string, not exceeding `len` characters */ /** Truncates and adds "..." to a string, not exceeding `len` characters */
std::string ellipsize(const std::string &s, size_t len); std::string ellipsize(const std::string &s, size_t len);
bool startsWith(const std::string &str, const std::string &prefix); bool startsWith(const std::string &str, const std::string &prefix);


+ 63
- 16
src/app/ModuleBrowser.cpp View File

@@ -11,6 +11,8 @@
#include "app/Scene.hpp" #include "app/Scene.hpp"
#include "plugin.hpp" #include "plugin.hpp"
#include "app.hpp" #include "app.hpp"
#include "plugin/Model.hpp"
#include "string.hpp"
#include "history.hpp" #include "history.hpp"


#include <set> #include <set>
@@ -24,6 +26,35 @@ namespace app {
static std::set<plugin::Model*> sFavoriteModels; static std::set<plugin::Model*> sFavoriteModels;





bool isMatch(const std::string &s, const std::string &search) {
std::string s2 = string::lowercase(s);
std::string search2 = string::lowercase(search);
return (s2.find(search2) != std::string::npos);
}

static bool isModelMatch(plugin::Model *model, const std::string &search) {
if (search.empty())
return true;
std::string s;
s += model->plugin->slug;
s += " ";
s += model->plugin->author;
s += " ";
s += model->plugin->name;
s += " ";
s += model->slug;
s += " ";
s += model->name;
for (const std::string &tag : model->tags) {
// TODO Normalize tag
s += tag;
s += " ";
}
return isMatch(s, search);
}


struct BrowserOverlay : widget::OpaqueWidget { struct BrowserOverlay : widget::OpaqueWidget {
void step() override { void step() override {
box = parent->box.zeroPos(); box = parent->box.zeroPos();
@@ -58,7 +89,7 @@ struct BrowserOverlay : widget::OpaqueWidget {
}; };




struct ModuleBox : widget::OpaqueWidget {
struct ModelBox : widget::OpaqueWidget {
plugin::Model *model; plugin::Model *model;
/** Lazily created */ /** Lazily created */
widget::Widget *previewWidget = NULL; widget::Widget *previewWidget = NULL;
@@ -150,6 +181,7 @@ struct ModuleBox : widget::OpaqueWidget {




struct BrowserSearchField : ui::TextField { struct BrowserSearchField : ui::TextField {
void onChange(const event::Change &e) override;
}; };




@@ -170,26 +202,26 @@ struct BrowserSidebar : widget::Widget {


struct ModuleBrowser : widget::OpaqueWidget { struct ModuleBrowser : widget::OpaqueWidget {
BrowserSidebar *sidebar; BrowserSidebar *sidebar;
ui::ScrollWidget *moduleScroll;
ui::SequentialLayout *moduleLayout;
ui::ScrollWidget *modelScroll;
ui::SequentialLayout *modelContainer;


ModuleBrowser() { ModuleBrowser() {
sidebar = new BrowserSidebar; sidebar = new BrowserSidebar;
sidebar->box.size.x = 300; sidebar->box.size.x = 300;
addChild(sidebar); addChild(sidebar);


moduleScroll = new ui::ScrollWidget;
addChild(moduleScroll);
modelScroll = new ui::ScrollWidget;
addChild(modelScroll);


moduleLayout = new ui::SequentialLayout;
moduleLayout->spacing = math::Vec(10, 10);
moduleScroll->container->addChild(moduleLayout);
modelContainer = new ui::SequentialLayout;
modelContainer->spacing = math::Vec(10, 10);
modelScroll->container->addChild(modelContainer);


for (plugin::Plugin *plugin : plugin::plugins) { for (plugin::Plugin *plugin : plugin::plugins) {
for (plugin::Model *model : plugin->models) { for (plugin::Model *model : plugin->models) {
ModuleBox *moduleBox = new ModuleBox;
ModelBox *moduleBox = new ModelBox;
moduleBox->setModel(model); moduleBox->setModel(model);
moduleLayout->addChild(moduleBox);
modelContainer->addChild(moduleBox);
} }
} }
} }
@@ -199,11 +231,11 @@ struct ModuleBrowser : widget::OpaqueWidget {


sidebar->box.size.y = box.size.y; sidebar->box.size.y = box.size.y;


moduleScroll->box.pos.x = sidebar->box.size.x;
moduleScroll->box.size.x = box.size.x - sidebar->box.size.x;
moduleScroll->box.size.y = box.size.y;
moduleLayout->box.size.x = moduleScroll->box.size.x;
moduleLayout->box.size.y = moduleLayout->getChildrenBoundingBox().getBottomRight().y;
modelScroll->box.pos.x = sidebar->box.size.x;
modelScroll->box.size.x = box.size.x - sidebar->box.size.x;
modelScroll->box.size.y = box.size.y;
modelContainer->box.size.x = modelScroll->box.size.x;
modelContainer->box.size.y = modelContainer->getChildrenBoundingBox().getBottomRight().y;


widget::OpaqueWidget::step(); widget::OpaqueWidget::step();
} }
@@ -212,13 +244,22 @@ struct ModuleBrowser : widget::OpaqueWidget {
bndMenuBackground(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, 0); bndMenuBackground(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, 0);
widget::Widget::draw(ctx); widget::Widget::draw(ctx);
} }

void setSearch(const std::string &search) {
for (Widget *w : modelContainer->children) {
ModelBox *modelBox = dynamic_cast<ModelBox*>(w);
assert(modelBox);
bool match = isModelMatch(modelBox->model, search);
modelBox->visible = match;
}
}
}; };




// Implementations to resolve dependencies // Implementations to resolve dependencies




void ModuleBox::onButton(const event::Button &e) {
void ModelBox::onButton(const event::Button &e) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) { if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) {
// Create module // Create module
ModuleWidget *moduleWidget = model->createModuleWidget(); ModuleWidget *moduleWidget = model->createModuleWidget();
@@ -241,6 +282,12 @@ void ModuleBox::onButton(const event::Button &e) {
widget::OpaqueWidget::onButton(e); widget::OpaqueWidget::onButton(e);
} }


void BrowserSearchField::onChange(const event::Change &e) {
ModuleBrowser *browser = getAncestorOfType<ModuleBrowser>();
browser->setSearch(text);
}




// Global functions // Global functions




+ 8
- 6
src/string.cpp View File

@@ -24,14 +24,16 @@ std::string f(const char *format, ...) {
return s; return s;
} }


std::string lowercase(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); });
return s;
std::string lowercase(const std::string &s) {
std::string r = s;
std::transform(r.begin(), r.end(), r.begin(), [](unsigned char c){ return std::tolower(c); });
return r;
} }


std::string uppercase(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::toupper(c); });
return s;
std::string uppercase(const std::string &s) {
std::string r = s;
std::transform(r.begin(), r.end(), r.begin(), [](unsigned char c){ return std::toupper(c); });
return r;
} }


std::string ellipsize(const std::string &s, size_t len) { std::string ellipsize(const std::string &s, size_t len) {


Loading…
Cancel
Save