Squash commits for public release

This commit is contained in:
2025-02-12 09:54:05 -05:00
commit 7118adc514
1108 changed files with 80873 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
#include "AppListView.h"
#include "AppListViewController.h"
#include "AppListWindow.h"
#include <libui/AppDelegate.h>
class AppDelegate : public UI::AppDelegate {
public:
AppDelegate() = default;
virtual ~AppDelegate() = default;
LG::Size preferred_desktop_window_size() const override { return LG::Size(320, 400); }
bool application() override
{
auto& window = std::xos::construct<AppListWindow>(window_size());
window.set_bitmap_format(LG::PixelBitmapFormat::RGBA);
auto& dock_view = window.create_superview<AppListView, AppListViewController>();
return true;
}
private:
};
SET_APP_DELEGATE(AppDelegate);

View File

@@ -0,0 +1,27 @@
#pragma once
#include <libg/PixelBitmap.h>
#include <list>
#include <string>
class AppEntity {
public:
AppEntity() = default;
void set_icon(LG::PixelBitmap&& icon) { m_icon = std::move(icon); }
const LG::PixelBitmap& icon() const { return m_icon; }
void set_title(const std::string& title) { m_title = title; }
const std::string& title() const { return m_title; }
void set_path_to_exec(const std::string& path) { m_path_to_exec = path; }
const std::string& path_to_exec() const { return m_path_to_exec; }
void set_bundle_id(const std::string& bid) { m_bundle_id = bid; }
const std::string& bundle_id() const { return m_bundle_id; }
private:
LG::PixelBitmap m_icon;
std::string m_title {};
std::string m_path_to_exec {};
std::string m_bundle_id {};
};

View File

@@ -0,0 +1,99 @@
#include "AppListView.h"
#include "IconView.h"
#include <algorithm>
#include <cstdlib>
#include <libfoundation/EventLoop.h>
#include <libfoundation/KeyboardMapping.h>
#include <libg/Color.h>
#include <libg/ImageLoaders/PNGLoader.h>
#include <libui/App.h>
#include <libui/CollectionView.h>
#include <libui/Context.h>
#include <libui/StackView.h>
#include <libui/TextField.h>
#include <unistd.h>
static AppListView* this_view;
AppListView::AppListView(UI::View* superview, const LG::Rect& frame)
: UI::View(superview, frame)
{
// Not used any more, reinit
// auto& dock_stack_view = add_subview<UI::StackView>(bounds());
// dock_stack_view.set_spacing(padding());
// dock_stack_view.set_background_color(LG::Color::Opaque);
// dock_stack_view.set_axis(UI::LayoutConstraints::Axis::Horizontal);
// dock_stack_view.set_distribution(UI::StackView::Distribution::EqualCentering);
// m_dock_stackview = &dock_stack_view;
}
AppListView::AppListView(UI::View* superview, UI::Window* window, const LG::Rect& frame)
: UI::View(superview, window, frame)
{
// Use manual layouting since layout is really simple here.
auto& header = add_subview<UI::View>(LG::Rect(0, 0, bounds().width(), 30 + 2 * padding()));
header.set_background_color(LG::Color::White);
header.layer().set_corner_mask(LG::CornerMask(8, LG::CornerMask::Masked, LG::CornerMask::NonMasked));
auto& searchbar = add_subview<UI::TextField>(LG::Rect(padding(), padding(), bounds().width() - padding() * 2, 30));
searchbar.layer().set_corner_mask(LG::CornerMask(8));
searchbar.set_background_color(LG::Color(0xE7F0FA));
searchbar.set_placeholder_text("SEARCH");
auto& applist_grid_view = add_subview<UI::CollectionView>(LG::Rect(0, 2 * padding() + 30, bounds().width(), bounds().height() - (2 * padding() + 30)));
applist_grid_view.set_data_source([this](int id) -> View* {
return this->view_streamer(id);
});
m_applist_grid_view = &applist_grid_view;
}
void AppListView::display(const LG::Rect& rect)
{
LG::Context ctx = UI::graphics_current_context();
ctx.add_clip(rect);
ctx.set_fill_color(background_color());
ctx.fill_rounded(bounds(), layer().corner_mask());
ctx.set_fill_color(LG::Color(120, 120, 120, 50));
ctx.draw_shading(LG::Rect(0, 30 + 2 * padding(), bounds().width(), 4), LG::Shading(LG::Shading::Type::TopToBottom));
}
UI::View* AppListView::view_streamer(int id)
{
if (id * items_per_row() >= m_app_entities.size()) {
return nullptr;
}
size_t calc_padding = (m_applist_grid_view->bounds().width() - 2 * padding() - (icon_view_size() * items_per_row())) / (items_per_row() - 1);
UI::StackView& dock_stack_view = m_applist_grid_view->add_subview<UI::StackView>(LG::Rect(padding(), 0, m_applist_grid_view->bounds().width() - 2 * padding(), icon_view_size() + calc_padding));
dock_stack_view.set_spacing(calc_padding);
dock_stack_view.set_background_color(LG::Color::Opaque);
dock_stack_view.set_axis(UI::LayoutConstraints::Axis::Horizontal);
dock_stack_view.set_distribution(UI::StackView::Distribution::Standard);
size_t rem = std::min(items_per_row(), (int)m_app_entities.size() - id * items_per_row());
for (int i = 0; i < rem; i++) {
auto& icon_view = dock_stack_view.add_arranged_subview<IconView>();
icon_view.set_title(m_app_entities[id * items_per_row() + i].title());
icon_view.entity() = m_app_entities[id * items_per_row() + i];
icon_view.add_constraint(UI::Constraint(icon_view, UI::Constraint::Attribute::Height, UI::Constraint::Relation::Equal, icon_view_size()));
icon_view.add_constraint(UI::Constraint(icon_view, UI::Constraint::Attribute::Width, UI::Constraint::Relation::Equal, icon_view_size()));
}
return &dock_stack_view;
}
void AppListView::register_entity(const AppEntity& ent)
{
m_app_entities.push_back(ent);
m_applist_grid_view->reload_data();
m_applist_grid_view->invalidate_row((m_app_entities.size() - 1) / items_per_row());
}
void AppListView::register_entity(AppEntity&& ent)
{
m_app_entities.push_back(std::move(ent));
m_applist_grid_view->reload_data();
m_applist_grid_view->invalidate_row((m_app_entities.size() - 1) / items_per_row());
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include "AppEntity.h"
#include "IconView.h"
#include <libg/Font.h>
#include <libui/CollectionView.h>
#include <libui/View.h>
#include <list>
#include <string>
class AppListView : public UI::View {
UI_OBJECT();
public:
AppListView(UI::View* superview, const LG::Rect& frame);
AppListView(UI::View* superview, UI::Window* window, const LG::Rect& frame);
static constexpr size_t padding() { return 16; }
static constexpr int icon_size() { return 32; }
static constexpr int icon_view_size() { return (int)64; }
static constexpr int items_per_row() { return (int)4; }
void display(const LG::Rect& rect) override;
void register_entity(const AppEntity& ent);
void register_entity(AppEntity&& ent);
private:
UI::View* view_streamer(int id);
UI::CollectionView* m_applist_grid_view {};
std::vector<AppEntity> m_app_entities {};
};

View File

@@ -0,0 +1,82 @@
#pragma once
#include "AppListView.h"
#include <libfoundation/FileManager.h>
#include <libfoundation/json/Parser.h>
#include <libg/ImageLoaders/PNGLoader.h>
#include <libui/App.h>
#include <libui/Button.h>
#include <libui/Label.h>
#include <libui/View.h>
#include <libui/ViewController.h>
#include <libui/Window.h>
#include <memory>
#include <sys/types.h>
char contentdir[256];
class AppListViewController : public UI::ViewController<AppListView> {
public:
AppListViewController(AppListView& view)
: UI::ViewController<AppListView>(view)
{
}
virtual ~AppListViewController() = default;
void load_application(const std::string& content_dir)
{
auto json_parser = LFoundation::Json::Parser(content_dir + "info.json");
LFoundation::Json::Object* jobj_root = json_parser.object();
if (jobj_root->invalid()) {
return;
}
auto* jdict_root = jobj_root->cast_to<LFoundation::Json::DictObject>();
const std::string& bundle_id = jdict_root->data()["bundle_id"]->cast_to<LFoundation::Json::StringObject>()->data();
AppEntity new_ent;
LG::PNG::PNGLoader loader;
std::string icon_path = jdict_root->data()["icon_path"]->cast_to<LFoundation::Json::StringObject>()->data();
new_ent.set_icon(loader.load_from_file(icon_path + "/32x32.png"));
std::string rel_exec_path = jdict_root->data()["exec_rel_path"]->cast_to<LFoundation::Json::StringObject>()->data();
new_ent.set_path_to_exec(content_dir + rel_exec_path);
new_ent.set_title(jdict_root->data()["name"]->cast_to<LFoundation::Json::StringObject>()->data());
new_ent.set_bundle_id(jdict_root->data()["bundle_id"]->cast_to<LFoundation::Json::StringObject>()->data());
view().register_entity(std::move(new_ent));
delete jdict_root;
}
void load_application_list()
{
auto local_fm = LFoundation::FileManager();
local_fm.foreach_object("/Applications", [this](const char* name) {
sprintf(contentdir, "/Applications/%s/Content/", name);
load_application(contentdir);
});
}
virtual void view_did_load() override
{
view().set_background_color(LG::Color::LightSystemOpaque);
view().layer().set_corner_mask(LG::CornerMask(4, LG::CornerMask::Masked, LG::CornerMask::NonMasked));
load_application_list();
#if 0
for (int i = 0; i < 32; i++) {
AppEntity new_ent;
LG::PNG::PNGLoader loader;
new_ent.set_icon(loader.load_from_file("/res/icons/apps/about.icon/32x32.png"));
new_ent.set_path_to_exec("/Applications/about.app/Content/about");
new_ent.set_title("TestApp");
new_ent.set_bundle_id("com.x.test");
view().register_entity(std::move(new_ent));
}
#endif
view().set_needs_display();
}
private:
};

View File

@@ -0,0 +1,7 @@
#include "AppListWindow.h"
#include "AppListView.h"
void AppListWindow::receive_event(std::unique_ptr<LFoundation::Event> event)
{
Window::receive_event(std::move(event));
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <libg/Size.h>
#include <libui/Screen.h>
#include <libui/Window.h>
class AppListWindow : public UI::Window {
public:
AppListWindow(const LG::Size& size)
: UI::Window("AppList", size, UI::WindowType::AppList)
{
}
void receive_event(std::unique_ptr<LFoundation::Event> event) override;
};

View File

@@ -0,0 +1,18 @@
import("//build/userland/TEMPLATE.gni")
xOS_executable("applist") {
install_path = "System/"
sources = [
"AppDelegate.cpp",
"AppListView.cpp",
"AppListWindow.cpp",
"IconView.cpp",
]
configs = [ "//build/userland:userland_flags" ]
deplibs = [
"libcxx",
"libfoundation",
"libg",
"libui",
]
}

View File

@@ -0,0 +1,38 @@
#include "IconView.h"
#include "AppListView.h"
#include <libui/App.h>
#include <libui/Context.h>
#include <libui/Label.h>
#include <libui/Screen.h>
#include <libui/Window.h>
IconView::IconView(View* superview, const LG::Rect& frame)
: View(superview, frame)
{
m_label = &add_subview<UI::Label>(LG::Rect(0, AppListView::icon_view_size() - 12, AppListView::icon_view_size(), 12));
m_label->set_alignment(UI::Text::Alignment::Center);
}
void IconView::display(const LG::Rect& rect)
{
const int padding = 4;
const int offset_x = (AppListView::icon_view_size() - AppListView::icon_size()) / 2;
const int offset_y = (AppListView::icon_view_size() - AppListView::icon_size()) / 2;
LG::Context ctx = UI::graphics_current_context();
ctx.add_clip(rect);
auto icon_rect = LG::Rect(offset_x, offset_y, AppListView::icon_size(), AppListView::icon_size());
ctx.draw(icon_rect.origin(), m_launch_entity.icon());
if (is_hovered()) {
ctx.set_fill_color(LG::Color::LightSystemOpaque128);
ctx.fill(icon_rect);
}
ctx.set_fill_color(LG::Color(120, 129, 133, 40));
ctx.draw_box_shading(icon_rect, LG::Shading(LG::Shading::Type::Box, 0, 3), LG::CornerMask(6));
}
void IconView::on_click()
{
launch();
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include "AppEntity.h"
#include <libg/Font.h>
#include <libui/Label.h>
#include <libui/PopupMenu.h>
#include <libui/View.h>
#include <list>
#include <string>
#include <unistd.h>
class IconView : public UI::View {
UI_OBJECT();
public:
IconView(View* superview, const LG::Rect& frame);
void display(const LG::Rect& rect) override;
void mouse_up() override { on_click(); }
static constexpr size_t underline_height() { return 4; }
void set_title(const std::string& title)
{
if (!m_label) {
return;
}
m_label->set_text(title);
}
AppEntity& entity() { return m_launch_entity; }
const AppEntity& entity() const { return m_launch_entity; }
virtual void mouse_entered(const LG::Point<int>& location) override
{
View::mouse_entered(location);
set_needs_display();
}
virtual void mouse_exited() override
{
View::mouse_exited();
set_needs_display();
}
private:
void on_click();
void launch()
{
if (fork() == 0) {
for (int i = 3; i < 32; i++) {
close(i);
}
execlp(m_launch_entity.path_to_exec().c_str(), m_launch_entity.path_to_exec().c_str(), NULL);
std::abort();
}
}
UI::Label* m_label;
AppEntity m_launch_entity;
};