mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 10:28:13 +00:00
SystemMenu: Untangle app/category discovery and GUI building
I was a bit confused by the fact that a method named `build_system_menu()` first enumerates a directory. Moving the app/category discovery to a dedicated function that returns the GUI-relevant information makes this process a bit less surprising. As an added bonus, `g_app_category_menus` was actually only a temporary mapping, and didn't need to be global. In theory, SystemMenu should use a handful fewer of bytes now.
This commit is contained in:
parent
e8ed7f829e
commit
404981a892
1 changed files with 28 additions and 24 deletions
|
@ -48,8 +48,6 @@ struct AppMetadata {
|
||||||
};
|
};
|
||||||
Vector<AppMetadata> g_apps;
|
Vector<AppMetadata> g_apps;
|
||||||
|
|
||||||
HashMap<String, NonnullRefPtr<GUI::Menu>> g_app_category_menus;
|
|
||||||
|
|
||||||
struct ThemeMetadata {
|
struct ThemeMetadata {
|
||||||
String name;
|
String name;
|
||||||
String path;
|
String path;
|
||||||
|
@ -61,6 +59,7 @@ Vector<ThemeMetadata> g_themes;
|
||||||
RefPtr<GUI::Menu> g_themes_menu;
|
RefPtr<GUI::Menu> g_themes_menu;
|
||||||
GUI::ActionGroup g_themes_group;
|
GUI::ActionGroup g_themes_group;
|
||||||
|
|
||||||
|
static Vector<String> discover_apps_and_categories();
|
||||||
static NonnullRefPtr<GUI::Menu> build_system_menu();
|
static NonnullRefPtr<GUI::Menu> build_system_menu();
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
|
@ -98,41 +97,46 @@ int main(int argc, char** argv)
|
||||||
return app->exec();
|
return app->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<GUI::Menu> build_system_menu()
|
Vector<String> discover_apps_and_categories()
|
||||||
{
|
{
|
||||||
HashTable<String> seen_app_categories;
|
HashTable<String> seen_app_categories;
|
||||||
{
|
Core::DirIterator dt("/res/apps", Core::DirIterator::SkipDots);
|
||||||
Core::DirIterator dt("/res/apps", Core::DirIterator::SkipDots);
|
while (dt.has_next()) {
|
||||||
while (dt.has_next()) {
|
auto af_name = dt.next_path();
|
||||||
auto af_name = dt.next_path();
|
auto af_path = String::format("/res/apps/%s", af_name.characters());
|
||||||
auto af_path = String::format("/res/apps/%s", af_name.characters());
|
auto af = Core::ConfigFile::open(af_path);
|
||||||
auto af = Core::ConfigFile::open(af_path);
|
if (!af->has_key("App", "Name") || !af->has_key("App", "Executable"))
|
||||||
if (!af->has_key("App", "Name") || !af->has_key("App", "Executable"))
|
continue;
|
||||||
continue;
|
auto app_name = af->read_entry("App", "Name");
|
||||||
auto app_name = af->read_entry("App", "Name");
|
auto app_executable = af->read_entry("App", "Executable");
|
||||||
auto app_executable = af->read_entry("App", "Executable");
|
auto app_category = af->read_entry("App", "Category");
|
||||||
auto app_category = af->read_entry("App", "Category");
|
auto app_icon_path = af->read_entry("Icons", "16x16");
|
||||||
auto app_icon_path = af->read_entry("Icons", "16x16");
|
g_apps.append({ app_executable, app_name, app_icon_path, app_category });
|
||||||
g_apps.append({ app_executable, app_name, app_icon_path, app_category });
|
seen_app_categories.set(app_category);
|
||||||
seen_app_categories.set(app_category);
|
|
||||||
}
|
|
||||||
quick_sort(g_apps, [](auto& a, auto& b) { return a.name < b.name; });
|
|
||||||
}
|
}
|
||||||
|
quick_sort(g_apps, [](auto& a, auto& b) { return a.name < b.name; });
|
||||||
|
|
||||||
Vector<String> sorted_app_categories;
|
Vector<String> sorted_app_categories;
|
||||||
for (auto& category : seen_app_categories)
|
for (auto& category : seen_app_categories) {
|
||||||
sorted_app_categories.append(category);
|
sorted_app_categories.append(category);
|
||||||
|
}
|
||||||
quick_sort(sorted_app_categories);
|
quick_sort(sorted_app_categories);
|
||||||
|
|
||||||
|
return sorted_app_categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<GUI::Menu> build_system_menu()
|
||||||
|
{
|
||||||
|
const Vector<String> sorted_app_categories = discover_apps_and_categories();
|
||||||
auto system_menu = GUI::Menu::construct("\xE2\x9A\xA1"); // HIGH VOLTAGE SIGN
|
auto system_menu = GUI::Menu::construct("\xE2\x9A\xA1"); // HIGH VOLTAGE SIGN
|
||||||
|
|
||||||
// First we construct all the necessary app category submenus.
|
// First we construct all the necessary app category submenus.
|
||||||
|
HashMap<String, NonnullRefPtr<GUI::Menu>> app_category_menus;
|
||||||
for (const auto& category : sorted_app_categories) {
|
for (const auto& category : sorted_app_categories) {
|
||||||
|
if (app_category_menus.contains(category))
|
||||||
if (g_app_category_menus.contains(category))
|
|
||||||
continue;
|
continue;
|
||||||
auto& category_menu = system_menu->add_submenu(category);
|
auto& category_menu = system_menu->add_submenu(category);
|
||||||
g_app_category_menus.set(category, category_menu);
|
app_category_menus.set(category, category_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then we create and insert all the app menu items into the right place.
|
// Then we create and insert all the app menu items into the right place.
|
||||||
|
@ -147,7 +151,7 @@ NonnullRefPtr<GUI::Menu> build_system_menu()
|
||||||
dbg() << "App " << app.name << " has icon with size " << icon->size();
|
dbg() << "App " << app.name << " has icon with size " << icon->size();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto parent_menu = g_app_category_menus.get(app.category).value_or(*system_menu);
|
auto parent_menu = app_category_menus.get(app.category).value_or(*system_menu);
|
||||||
parent_menu->add_action(GUI::Action::create(app.name, icon.ptr(), [app_identifier](auto&) {
|
parent_menu->add_action(GUI::Action::create(app.name, icon.ptr(), [app_identifier](auto&) {
|
||||||
dbg() << "Activated app with ID " << app_identifier;
|
dbg() << "Activated app with ID " << app_identifier;
|
||||||
const auto& bin = g_apps[app_identifier].executable;
|
const auto& bin = g_apps[app_identifier].executable;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue