Squash commits for public release
This commit is contained in:
5
userland/applications/about/.info.mk
Normal file
5
userland/applications/about/.info.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
APPS += ABOUT
|
||||
|
||||
ABOUT_NAME = about
|
||||
ABOUT_LIBS = cxx ui
|
||||
ABOUT_INSTALL_PATH = bin/
|
||||
64
userland/applications/about/AboutLineView.h
Normal file
64
userland/applications/about/AboutLineView.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include <libg/Font.h>
|
||||
#include <libui/Label.h>
|
||||
#include <libui/View.h>
|
||||
#include <string>
|
||||
|
||||
class AboutLineView : public UI::View {
|
||||
UI_OBJECT();
|
||||
|
||||
public:
|
||||
AboutLineView(UI::View* superview, const LG::Rect& frame, std::string title, std::string content)
|
||||
: UI::View(superview, frame)
|
||||
, m_title(title)
|
||||
, m_content(content)
|
||||
{
|
||||
const int spacing = 4;
|
||||
set_background_color(LG::Color::LightSystemBackground);
|
||||
|
||||
auto& label = add_subview<UI::Label>(LG::Rect(0, 0, 16, 16));
|
||||
label.set_text_color(LG::Color::DarkSystemText);
|
||||
label.set_text(m_title);
|
||||
label.set_width(label.preferred_width());
|
||||
|
||||
auto& target_label = add_subview<UI::Label>(LG::Rect(0, 0, 16, 16));
|
||||
target_label.set_text_color(LG::Color::DarkSystemText);
|
||||
target_label.set_text(m_content);
|
||||
target_label.set_width(target_label.preferred_width());
|
||||
|
||||
add_constraint(UI::Constraint(target_label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, label, UI::Constraint::Attribute::Right, 1, spacing));
|
||||
add_constraint(UI::Constraint(target_label, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, label, UI::Constraint::Attribute::Top, 1, 0));
|
||||
|
||||
set_width(label.preferred_width() + spacing + target_label.preferred_width());
|
||||
}
|
||||
|
||||
AboutLineView(UI::View* superview, UI::Window* window, const LG::Rect& frame, std::string title, std::string content)
|
||||
: UI::View(superview, window, frame)
|
||||
, m_title(title)
|
||||
, m_content(content)
|
||||
{
|
||||
const int spacing = 4;
|
||||
set_background_color(LG::Color::LightSystemBackground);
|
||||
|
||||
auto& label = add_subview<UI::Label>(LG::Rect(0, 0, 16, 16));
|
||||
label.set_text_color(LG::Color::DarkSystemText);
|
||||
label.set_text(m_title);
|
||||
label.set_width(label.preferred_width());
|
||||
|
||||
auto& target_label = add_subview<UI::Label>(LG::Rect(0, 0, 16, 16));
|
||||
target_label.set_text_color(LG::Color::DarkSystemText);
|
||||
target_label.set_text(m_content);
|
||||
target_label.set_width(target_label.preferred_width());
|
||||
|
||||
add_constraint(UI::Constraint(target_label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, label, UI::Constraint::Attribute::Right, 1, spacing));
|
||||
add_constraint(UI::Constraint(target_label, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, label, UI::Constraint::Attribute::Top, 1, 0));
|
||||
|
||||
set_width(label.preferred_width() + spacing + target_label.preferred_width());
|
||||
}
|
||||
|
||||
~AboutLineView() = default;
|
||||
|
||||
private:
|
||||
std::string m_title {};
|
||||
std::string m_content {};
|
||||
};
|
||||
29
userland/applications/about/AppDelegate.cpp
Normal file
29
userland/applications/about/AppDelegate.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "ViewController.h"
|
||||
#include <libui/AppDelegate.h>
|
||||
#include <libui/MenuBar.h>
|
||||
|
||||
class AppDelegate : public UI::AppDelegate {
|
||||
public:
|
||||
AppDelegate() = default;
|
||||
virtual ~AppDelegate() = default;
|
||||
|
||||
LG::Size preferred_desktop_window_size() const override { return LG::Size(200, 210); }
|
||||
const char* icon_path() const override { return "/res/icons/apps/about.icon"; }
|
||||
|
||||
virtual bool application() override
|
||||
{
|
||||
auto style = StatusBarStyle(LG::Color(231, 240, 250)).set_hide_text();
|
||||
auto& window = std::xos::construct<UI::Window>("About", window_size(), icon_path(), style);
|
||||
auto& superview = window.create_superview<UI::View, ViewController>();
|
||||
|
||||
auto demo_menu = UI::Menu("Demo");
|
||||
demo_menu.add_item(UI::MenuItem("Say hello", [] { Logger::debug << "Hello!" << std::endl; }));
|
||||
window.menubar().add_menu(std::move(demo_menu));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
SET_APP_DELEGATE(AppDelegate);
|
||||
17
userland/applications/about/BUILD.gn
Normal file
17
userland/applications/about/BUILD.gn
Normal file
@@ -0,0 +1,17 @@
|
||||
import("//build/userland/TEMPLATE.gni")
|
||||
|
||||
xOS_application("about") {
|
||||
display_name = "About"
|
||||
sources = [
|
||||
"AppDelegate.cpp",
|
||||
]
|
||||
configs = [
|
||||
"//build/userland:userland_flags",
|
||||
]
|
||||
deplibs = [
|
||||
"libcxx",
|
||||
"libfoundation",
|
||||
"libg",
|
||||
"libui"
|
||||
]
|
||||
}
|
||||
78
userland/applications/about/ViewController.h
Normal file
78
userland/applications/about/ViewController.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
#include "AboutLineView.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>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
class ViewController : public UI::ViewController<UI::View> {
|
||||
public:
|
||||
ViewController(UI::View& view)
|
||||
: UI::ViewController<UI::View>(view)
|
||||
{
|
||||
}
|
||||
virtual ~ViewController() = default;
|
||||
|
||||
void view_did_load() override
|
||||
{
|
||||
view().set_background_color(LG::Color::LightSystemBackground);
|
||||
|
||||
utsname_t uts;
|
||||
int rc = uname(&uts);
|
||||
|
||||
auto& header = view().add_subview<UI::View>(LG::Rect(0, 0, 0, 0));
|
||||
header.set_background_color(LG::Color(231, 240, 250));
|
||||
|
||||
auto& label = header.add_subview<UI::Label>(LG::Rect(0, 0, 16, 22));
|
||||
label.set_text("About");
|
||||
label.set_text_color(LG::Color(35, 70, 106));
|
||||
label.set_font(LG::Font::system_bold_font(LG::Font::SystemTitleSize));
|
||||
label.set_width(label.preferred_width());
|
||||
|
||||
auto& name_label = view().add_subview<AboutLineView>(LG::Rect(0, 0, 16, 16), "Name:", uts.sysname);
|
||||
auto& cpu_label = view().add_subview<AboutLineView>(LG::Rect(0, 0, 16, 16), "CPU:", uts.machine);
|
||||
auto& version_label = view().add_subview<AboutLineView>(LG::Rect(0, 0, 16, 16), "Version:", uts.release);
|
||||
|
||||
auto& button = view().add_subview<UI::Button>(LG::Rect(0, 0, 10, 10));
|
||||
button.set_background_color(LG::Color::LightSystemButton);
|
||||
button.set_title("System info");
|
||||
button.set_title_color(LG::Color::DarkSystemText);
|
||||
|
||||
auto& footer = view().add_subview<UI::Label>(LG::Rect(0, 0, 16, 16));
|
||||
footer.set_text_color(LG::Color::DarkSystemText);
|
||||
footer.set_text("(c) 2020-2023");
|
||||
footer.set_width(footer.preferred_width());
|
||||
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, 0));
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, 0));
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Right, UI::Constraint::Relation::Equal, 0));
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Height, UI::Constraint::Relation::Equal, 60));
|
||||
|
||||
view().add_constraint(UI::Constraint(label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(label, UI::Constraint::Attribute::CenterY, UI::Constraint::Relation::Equal, header, UI::Constraint::Attribute::CenterY, 1, 0));
|
||||
|
||||
view().add_constraint(UI::Constraint(name_label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(name_label, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, header, UI::Constraint::Attribute::Bottom, 1, UI::Padding::AfterTitle));
|
||||
|
||||
view().add_constraint(UI::Constraint(cpu_label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(cpu_label, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, name_label, UI::Constraint::Attribute::Bottom, 1, 4));
|
||||
|
||||
view().add_constraint(UI::Constraint(version_label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(version_label, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, cpu_label, UI::Constraint::Attribute::Bottom, 1, 4));
|
||||
|
||||
view().add_constraint(UI::Constraint(button, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(button, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, version_label, UI::Constraint::Attribute::Bottom, 1, 8));
|
||||
|
||||
view().add_constraint(UI::Constraint(footer, UI::Constraint::Attribute::CenterX, UI::Constraint::Relation::Equal, view(), UI::Constraint::Attribute::CenterX, 1, 0));
|
||||
view().add_constraint(UI::Constraint(footer, UI::Constraint::Attribute::Bottom, UI::Constraint::Relation::Equal, view(), UI::Constraint::Attribute::Bottom, 1, -UI::SafeArea::Bottom));
|
||||
|
||||
view().set_needs_layout();
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
23
userland/applications/activity_monitor/AppDelegate.cpp
Normal file
23
userland/applications/activity_monitor/AppDelegate.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "ViewController.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(220, 210); }
|
||||
const char* icon_path() const override { return "/res/icons/apps/activity_monitor.icon"; }
|
||||
|
||||
virtual bool application() override
|
||||
{
|
||||
auto style = StatusBarStyle(LG::Color(222, 232, 227)).set_hide_text();
|
||||
auto& window = std::xos::construct<UI::Window>("Monitor", window_size(), icon_path(), style);
|
||||
auto& superview = window.create_superview<UI::View, ViewController>();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
SET_APP_DELEGATE(AppDelegate);
|
||||
16
userland/applications/activity_monitor/BUILD.gn
Normal file
16
userland/applications/activity_monitor/BUILD.gn
Normal file
@@ -0,0 +1,16 @@
|
||||
import("//build/userland/TEMPLATE.gni")
|
||||
|
||||
xOS_application("activity_monitor") {
|
||||
display_name = "Monitor"
|
||||
sources = [
|
||||
"AppDelegate.cpp",
|
||||
"GraphView.cpp",
|
||||
]
|
||||
configs = [ "//build/userland:userland_flags" ]
|
||||
deplibs = [
|
||||
"libcxx",
|
||||
"libfoundation",
|
||||
"libg",
|
||||
"libui",
|
||||
]
|
||||
}
|
||||
40
userland/applications/activity_monitor/GraphView.cpp
Normal file
40
userland/applications/activity_monitor/GraphView.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "GraphView.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <libfoundation/EventLoop.h>
|
||||
#include <libfoundation/KeyboardMapping.h>
|
||||
#include <libg/Color.h>
|
||||
#include <libui/Context.h>
|
||||
|
||||
GraphView::GraphView(UI::View* superview, const LG::Rect& frame, int data_size)
|
||||
: UI::View(superview, frame)
|
||||
, m_data(data_size)
|
||||
{
|
||||
for (int i = 0; i < data_size; i++) {
|
||||
m_data.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::display(const LG::Rect& rect)
|
||||
{
|
||||
LG::Context ctx = UI::graphics_current_context();
|
||||
ctx.add_clip(rect);
|
||||
|
||||
ctx.set_fill_color(LG::Color(233, 233, 233));
|
||||
ctx.fill(bounds());
|
||||
|
||||
ctx.set_fill_color(LG::Color(14, 72, 19));
|
||||
|
||||
size_t left_padding = bounds().width();
|
||||
size_t height = bounds().height();
|
||||
size_t column_width = 3;
|
||||
|
||||
for (int i = m_data.size() - 1; i >= 0; i--) {
|
||||
left_padding -= column_width;
|
||||
size_t column_height = (m_data[i] * height) / 100;
|
||||
ctx.fill(LG::Rect(left_padding, height - column_height, column_width, column_height));
|
||||
if (left_padding < column_width) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
userland/applications/activity_monitor/GraphView.h
Normal file
25
userland/applications/activity_monitor/GraphView.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <libg/Font.h>
|
||||
#include <libui/View.h>
|
||||
#include <string>
|
||||
|
||||
class GraphView : public UI::View {
|
||||
UI_OBJECT();
|
||||
|
||||
public:
|
||||
GraphView(UI::View* superview, const LG::Rect&, int data_size);
|
||||
|
||||
void display(const LG::Rect& rect) override;
|
||||
|
||||
void add_new_value(int val)
|
||||
{
|
||||
for (int i = 0; i < m_data.size() - 1; i++) {
|
||||
m_data[i] = m_data[i + 1];
|
||||
}
|
||||
m_data[m_data.size() - 1] = val;
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<int> m_data;
|
||||
};
|
||||
150
userland/applications/activity_monitor/ViewController.h
Normal file
150
userland/applications/activity_monitor/ViewController.h
Normal file
@@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
#include "GraphView.h"
|
||||
#include <libfoundation/ProcessInfo.h>
|
||||
#include <libui/App.h>
|
||||
#include <libui/Button.h>
|
||||
#include <libui/Label.h>
|
||||
#include <libui/StackView.h>
|
||||
#include <libui/View.h>
|
||||
#include <libui/ViewController.h>
|
||||
#include <libui/Window.h>
|
||||
#include <memory>
|
||||
#include <sys/types.h>
|
||||
|
||||
static char buf[256];
|
||||
|
||||
class ViewController : public UI::ViewController<UI::View> {
|
||||
public:
|
||||
ViewController(UI::View& view)
|
||||
: UI::ViewController<UI::View>(view)
|
||||
, m_cpu_count(LFoundation::ProcessInfo::the().processor_count())
|
||||
{
|
||||
}
|
||||
virtual ~ViewController() = default;
|
||||
|
||||
inline int cpu_count() const { return m_cpu_count; }
|
||||
|
||||
void view_did_load() override
|
||||
{
|
||||
state.cpu_load.resize(cpu_count());
|
||||
state.cpu_old_user_time.resize(cpu_count());
|
||||
state.cpu_old_system_time.resize(cpu_count());
|
||||
state.cpu_old_idle_time.resize(cpu_count());
|
||||
|
||||
view().set_background_color(LG::Color::LightSystemBackground);
|
||||
|
||||
auto& header = view().add_subview<UI::View>(LG::Rect(0, 0, 0, 0));
|
||||
header.set_background_color(LG::Color(222, 232, 227));
|
||||
|
||||
auto& label = header.add_subview<UI::Label>(LG::Rect(0, 0, 16, 22));
|
||||
label.set_text_color(LG::Color(14, 72, 19));
|
||||
label.set_text("Monitor");
|
||||
label.set_font(LG::Font::system_bold_font(LG::Font::SystemTitleSize));
|
||||
label.set_width(label.preferred_width());
|
||||
|
||||
auto& switch_tab = view().add_subview<UI::StackView>(LG::Rect(0, 0, 102, 18));
|
||||
switch_tab.set_spacing(8);
|
||||
switch_tab.layer().set_corner_mask(LG::CornerMask(4));
|
||||
switch_tab.layer().set_shading(LG::Shading(LG::Shading::Box));
|
||||
switch_tab.set_spacing(4);
|
||||
|
||||
auto& cpu_tab = switch_tab.add_arranged_subview<UI::Button>();
|
||||
cpu_tab.set_content_edge_insets(UI::EdgeInsets(4, 10, 4, 10));
|
||||
cpu_tab.set_background_color(LG::Color(248, 250, 231));
|
||||
cpu_tab.set_title("CPU");
|
||||
cpu_tab.set_title_color(LG::Color::DarkSystemText);
|
||||
|
||||
auto& mem_tab = switch_tab.add_arranged_subview<UI::Button>();
|
||||
mem_tab.set_content_edge_insets(UI::EdgeInsets(4, 10, 4, 10));
|
||||
mem_tab.set_background_color(LG::Color::White);
|
||||
mem_tab.set_title("Memory");
|
||||
mem_tab.set_title_color(LG::Color::DarkSystemText);
|
||||
|
||||
auto& cpu_label = view().add_subview<UI::Label>(LG::Rect(0, 0, 180, 16));
|
||||
auto& cpu_graphs_stackview = view().add_subview<UI::StackView>(LG::Rect(0, 0, 184, 100));
|
||||
cpu_graphs_stackview.set_distribution(UI::StackView::Distribution::FillEqually);
|
||||
cpu_graphs_stackview.set_spacing(10);
|
||||
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, 0));
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, 0));
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Right, UI::Constraint::Relation::Equal, 0));
|
||||
view().add_constraint(UI::Constraint(header, UI::Constraint::Attribute::Height, UI::Constraint::Relation::Equal, 60));
|
||||
|
||||
view().add_constraint(UI::Constraint(label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(label, UI::Constraint::Attribute::CenterY, UI::Constraint::Relation::Equal, header, UI::Constraint::Attribute::CenterY, 1, 0));
|
||||
|
||||
view().add_constraint(UI::Constraint(switch_tab, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(switch_tab, UI::Constraint::Attribute::CenterY, UI::Constraint::Relation::Equal, header, UI::Constraint::Attribute::Bottom, 1, 0));
|
||||
|
||||
view().add_constraint(UI::Constraint(cpu_label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(cpu_label, UI::Constraint::Attribute::Bottom, UI::Constraint::Relation::Equal, UI::SafeArea::Bottom));
|
||||
|
||||
view().add_constraint(UI::Constraint(cpu_graphs_stackview, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(cpu_graphs_stackview, UI::Constraint::Attribute::Right, UI::Constraint::Relation::Equal, UI::SafeArea::Right));
|
||||
view().add_constraint(UI::Constraint(cpu_graphs_stackview, UI::Constraint::Attribute::Top, UI::Constraint::Relation::Equal, switch_tab, UI::Constraint::Attribute::Bottom, 1, 8));
|
||||
view().add_constraint(UI::Constraint(cpu_graphs_stackview, UI::Constraint::Attribute::Bottom, UI::Constraint::Relation::Equal, cpu_label, UI::Constraint::Attribute::Top, 1, -8));
|
||||
|
||||
for (int i = 0; i < cpu_count(); i++) {
|
||||
auto& graph = cpu_graphs_stackview.add_arranged_subview<GraphView>(200);
|
||||
cpu_graphs_stackview.add_constraint(UI::Constraint(graph, UI::Constraint::Attribute::Height, UI::Constraint::Relation::Equal, cpu_graphs_stackview, UI::Constraint::Attribute::Height, 1, 0));
|
||||
cpu_graphs.push_back(&graph);
|
||||
}
|
||||
|
||||
view().set_needs_layout();
|
||||
|
||||
UI::App::the().event_loop().add(LFoundation::Timer([&] {
|
||||
update_data();
|
||||
cpu_label.set_text(std::string("Load ") + std::to_string(state.cpu_load[0]) + "%");
|
||||
cpu_label.set_needs_display();
|
||||
},
|
||||
1000, LFoundation::Timer::Repeat));
|
||||
}
|
||||
|
||||
int update_cpu_load()
|
||||
{
|
||||
int fd_proc_stat = open("/proc/stat", O_RDONLY);
|
||||
int offset = 0;
|
||||
read(fd_proc_stat, buf, sizeof(buf));
|
||||
|
||||
for (int i = 0; i < cpu_count(); i++) {
|
||||
int user_time, system_time, idle_time;
|
||||
int num;
|
||||
offset += sscanf(buf + offset, "cpu%d %d 0 %d %d\n", &num, &user_time, &system_time, &idle_time);
|
||||
int diff_user_time = user_time - state.cpu_old_user_time[i];
|
||||
int diff_system_time = system_time - state.cpu_old_system_time[i];
|
||||
int diff_idle_time = idle_time - state.cpu_old_idle_time[i];
|
||||
state.cpu_old_user_time[i] = user_time;
|
||||
state.cpu_old_system_time[i] = system_time;
|
||||
state.cpu_old_idle_time[i] = idle_time;
|
||||
|
||||
if (diff_user_time + diff_system_time + diff_idle_time == 0) {
|
||||
state.cpu_load[i] = 0;
|
||||
} else {
|
||||
state.cpu_load[i] = (diff_user_time + diff_system_time) * 100 / (diff_user_time + diff_system_time + diff_idle_time);
|
||||
}
|
||||
|
||||
cpu_graphs[i]->add_new_value(state.cpu_load[i]);
|
||||
}
|
||||
|
||||
close(fd_proc_stat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void update_data()
|
||||
{
|
||||
update_cpu_load();
|
||||
}
|
||||
|
||||
private:
|
||||
int m_cpu_count;
|
||||
int fd_proc_stat;
|
||||
std::vector<GraphView*> cpu_graphs;
|
||||
|
||||
struct State {
|
||||
std::vector<int> cpu_load;
|
||||
std::vector<int> cpu_old_user_time;
|
||||
std::vector<int> cpu_old_system_time;
|
||||
std::vector<int> cpu_old_idle_time;
|
||||
};
|
||||
State state;
|
||||
};
|
||||
5
userland/applications/calculator/.info.mk
Normal file
5
userland/applications/calculator/.info.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
APPS += CALCULATOR
|
||||
|
||||
ABOUT_NAME = calculator
|
||||
ABOUT_LIBS = cxx ui
|
||||
ABOUT_INSTALL_PATH = bin/
|
||||
22
userland/applications/calculator/AppDelegate.cpp
Normal file
22
userland/applications/calculator/AppDelegate.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "ViewController.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(240, 340); }
|
||||
const char* icon_path() const override { return "/res/icons/apps/calculator.icon"; }
|
||||
|
||||
virtual bool application() override
|
||||
{
|
||||
auto& window = std::xos::construct<UI::Window>("Calculator", window_size(), icon_path());
|
||||
auto& superview = window.create_superview<UI::View, ViewController>();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
SET_APP_DELEGATE(AppDelegate);
|
||||
17
userland/applications/calculator/BUILD.gn
Normal file
17
userland/applications/calculator/BUILD.gn
Normal file
@@ -0,0 +1,17 @@
|
||||
import("//build/userland/TEMPLATE.gni")
|
||||
|
||||
xOS_application("calculator") {
|
||||
display_name = "Calculator"
|
||||
sources = [
|
||||
"AppDelegate.cpp",
|
||||
]
|
||||
configs = [
|
||||
"//build/userland:userland_flags",
|
||||
]
|
||||
deplibs = [
|
||||
"libcxx",
|
||||
"libfoundation",
|
||||
"libg",
|
||||
"libui"
|
||||
]
|
||||
}
|
||||
179
userland/applications/calculator/ViewController.h
Normal file
179
userland/applications/calculator/ViewController.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#pragma once
|
||||
#include <libui/App.h>
|
||||
#include <libui/Button.h>
|
||||
#include <libui/Label.h>
|
||||
#include <libui/StackView.h>
|
||||
#include <libui/View.h>
|
||||
#include <libui/ViewController.h>
|
||||
#include <libui/Window.h>
|
||||
#include <memory>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
// TODO: Add enum for colors.
|
||||
|
||||
class ViewController : public UI::ViewController<UI::View> {
|
||||
public:
|
||||
ViewController(UI::View& view)
|
||||
: UI::ViewController<UI::View>(view)
|
||||
{
|
||||
}
|
||||
virtual ~ViewController() = default;
|
||||
|
||||
static constexpr const char* button_titles[20] = {
|
||||
"c",
|
||||
"+/-",
|
||||
"%",
|
||||
"/",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"*",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"-",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"+",
|
||||
"0",
|
||||
"00",
|
||||
",",
|
||||
"=",
|
||||
};
|
||||
|
||||
constexpr size_t button_size() { return 48; }
|
||||
constexpr size_t spacing_size() { return 8; }
|
||||
|
||||
bool is_operation(char a) { return a == '*' || a == '/' || a == '+' || a == '-'; }
|
||||
|
||||
void on_button_click(UI::Button* sender)
|
||||
{
|
||||
// Check if it is a number
|
||||
if (sender->title().size() == 1 && '0' <= sender->title()[0] && sender->title()[0] <= '9') {
|
||||
m_current_number.push_back(sender->title()[0]);
|
||||
m_answer_label_ptr->set_text(m_current_number);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it is an operation
|
||||
if (sender->title().size() == 1 && is_operation(sender->title()[0])) {
|
||||
var_number1 = std::atoi(m_current_number.c_str());
|
||||
m_current_number.clear();
|
||||
m_operation = sender->title()[0];
|
||||
m_active_operation_button = sender;
|
||||
sender->set_background_color(LG::Color(165, 201, 242));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender->title().size() == 1 && sender->title()[0] == '=') {
|
||||
int var_number2 = std::atoi(m_current_number.c_str());
|
||||
switch (m_operation) {
|
||||
case '+':
|
||||
var_number1 = var_number1 + var_number2;
|
||||
m_current_number = std::to_string(var_number1);
|
||||
m_answer_label_ptr->set_text(m_current_number);
|
||||
m_active_operation_button->set_background_color(LG::Color(231, 240, 250));
|
||||
break;
|
||||
case '-':
|
||||
var_number1 = var_number1 - var_number2;
|
||||
m_current_number = std::to_string(var_number1);
|
||||
m_answer_label_ptr->set_text(m_current_number);
|
||||
m_active_operation_button->set_background_color(LG::Color(231, 240, 250));
|
||||
break;
|
||||
case '*':
|
||||
var_number1 = var_number1 * var_number2;
|
||||
m_current_number = std::to_string(var_number1);
|
||||
m_answer_label_ptr->set_text(m_current_number);
|
||||
m_active_operation_button->set_background_color(LG::Color(231, 240, 250));
|
||||
break;
|
||||
case '/':
|
||||
m_active_operation_button->set_background_color(LG::Color(231, 240, 250));
|
||||
if (var_number2 == 0) {
|
||||
m_current_number = "";
|
||||
m_answer_label_ptr->set_text("Error");
|
||||
return;
|
||||
}
|
||||
var_number1 = var_number1 / var_number2;
|
||||
m_current_number = std::to_string(var_number1);
|
||||
m_answer_label_ptr->set_text(m_current_number);
|
||||
break;
|
||||
default:
|
||||
m_current_number = "";
|
||||
m_answer_label_ptr->set_text("Error");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender->title().size() == 1 && sender->title()[0] == 'c') {
|
||||
m_operation = ' ';
|
||||
m_active_operation_button = nullptr;
|
||||
m_answer_label_ptr->set_text("0");
|
||||
m_current_number.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void view_did_load() override
|
||||
{
|
||||
view().set_background_color(LG::Color::LightSystemBackground);
|
||||
|
||||
auto& main_stackview = view().add_subview<UI::StackView>(LG::Rect(0, 0, 0, button_size() * 5 + spacing_size() * 4));
|
||||
main_stackview.set_background_color(LG::Color::LightSystemBackground);
|
||||
main_stackview.set_axis(UI::LayoutConstraints::Axis::Vertical);
|
||||
main_stackview.set_spacing(spacing_size());
|
||||
view().add_constraint(UI::Constraint(main_stackview, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(main_stackview, UI::Constraint::Attribute::Right, UI::Constraint::Relation::Equal, UI::SafeArea::Right));
|
||||
view().add_constraint(UI::Constraint(main_stackview, UI::Constraint::Attribute::Bottom, UI::Constraint::Relation::Equal, UI::SafeArea::Bottom));
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
auto& stackview = main_stackview.add_arranged_subview<UI::StackView>();
|
||||
stackview.set_background_color(LG::Color::LightSystemBackground);
|
||||
stackview.set_distribution(UI::StackView::Distribution::EqualSpacing);
|
||||
main_stackview.add_constraint(UI::Constraint(stackview, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, main_stackview, UI::Constraint::Attribute::Left, 1, 0));
|
||||
main_stackview.add_constraint(UI::Constraint(stackview, UI::Constraint::Attribute::Right, UI::Constraint::Relation::Equal, main_stackview, UI::Constraint::Attribute::Right, 1, 0));
|
||||
main_stackview.add_constraint(UI::Constraint(stackview, UI::Constraint::Attribute::Height, UI::Constraint::Relation::Equal, button_size()));
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
auto& view1 = stackview.add_arranged_subview<UI::Button>();
|
||||
if (j == 3 && i == 4) {
|
||||
view1.set_background_color(LG::Color(198, 166, 242));
|
||||
view1.set_title_color(LG::Color::White);
|
||||
} else if (j == 3 || i == 0) {
|
||||
view1.set_background_color(LG::Color(231, 240, 250));
|
||||
view1.set_title_color(LG::Color(35, 70, 106));
|
||||
} else {
|
||||
view1.set_background_color(LG::Color::LightSystemButton);
|
||||
view1.set_title_color(LG::Color::DarkSystemText);
|
||||
}
|
||||
view1.set_font(LG::Font::system_bold_font(14));
|
||||
view1.set_title(button_titles[i * 4 + j]);
|
||||
view1.set_alignment(UI::Text::Alignment::Center);
|
||||
view1.add_target([this](UI::View* sender) { this->on_button_click(static_cast<UI::Button*>(sender)); }, UI::Event::Type::MouseUpEvent);
|
||||
view1.layer().set_corner_mask(LG::CornerMask(button_size() / 2));
|
||||
stackview.add_constraint(UI::Constraint(view1, UI::Constraint::Attribute::Height, UI::Constraint::Relation::Equal, button_size()));
|
||||
stackview.add_constraint(UI::Constraint(view1, UI::Constraint::Attribute::Width, UI::Constraint::Relation::Equal, button_size()));
|
||||
}
|
||||
}
|
||||
|
||||
auto& answer_label = view().add_subview<UI::Label>(LG::Rect(0, 0, 0, 40));
|
||||
answer_label.set_text("0");
|
||||
answer_label.set_text_color(LG::Color::DarkSystemText);
|
||||
answer_label.set_alignment(UI::Text::Alignment::Right);
|
||||
answer_label.set_font(LG::Font::system_font(36));
|
||||
m_answer_label_ptr = &answer_label;
|
||||
view().add_constraint(UI::Constraint(answer_label, UI::Constraint::Attribute::Left, UI::Constraint::Relation::Equal, UI::SafeArea::Left));
|
||||
view().add_constraint(UI::Constraint(answer_label, UI::Constraint::Attribute::Right, UI::Constraint::Relation::Equal, UI::SafeArea::Right));
|
||||
view().add_constraint(UI::Constraint(answer_label, UI::Constraint::Attribute::Bottom, UI::Constraint::Relation::Equal, main_stackview, UI::Constraint::Attribute::Top, 1, -8));
|
||||
|
||||
view().set_needs_layout();
|
||||
}
|
||||
|
||||
private:
|
||||
UI::Label* m_answer_label_ptr { nullptr };
|
||||
std::string m_current_number;
|
||||
int var_number1 { 0 };
|
||||
char m_operation;
|
||||
UI::Button* m_active_operation_button { nullptr };
|
||||
};
|
||||
5
userland/applications/terminal/.info.mk
Normal file
5
userland/applications/terminal/.info.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
APPS += TERMINAL
|
||||
|
||||
TERMINAL_NAME = terminal
|
||||
TERMINAL_LIBS = cxx ui
|
||||
TERMINAL_INSTALL_PATH = bin/
|
||||
62
userland/applications/terminal/AppDelegate.cpp
Normal file
62
userland/applications/terminal/AppDelegate.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "TerminalView.h"
|
||||
#include "TerminalViewController.h"
|
||||
#include <csignal>
|
||||
#include <libui/AppDelegate.h>
|
||||
|
||||
static int shell_pid = 0;
|
||||
|
||||
int setup_shell()
|
||||
{
|
||||
int ptmx = posix_openpt(O_RDONLY);
|
||||
if (ptmx < 0) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
int f = fork();
|
||||
if (f == 0) {
|
||||
char* pname = ptsname(ptmx);
|
||||
if (!pname) {
|
||||
return -1;
|
||||
}
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
open(pname, O_RDONLY);
|
||||
open(pname, O_WRONLY);
|
||||
open(pname, O_WRONLY);
|
||||
execlp("/bin/tinysh", "/bin/tinysh", NULL);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
shell_pid = f;
|
||||
return ptmx;
|
||||
}
|
||||
|
||||
class AppDelegate : public UI::AppDelegate {
|
||||
public:
|
||||
AppDelegate() = default;
|
||||
virtual ~AppDelegate() = default;
|
||||
|
||||
LG::Size preferred_desktop_window_size() const override { return LG::Size(400, 300); }
|
||||
const char* icon_path() const override { return "/res/icons/apps/terminal.icon"; }
|
||||
|
||||
bool application() override
|
||||
{
|
||||
int ptmx = setup_shell();
|
||||
auto style = StatusBarStyle(LG::Color(58, 58, 64)).set_light_text();
|
||||
auto& window = std::xos::construct<UI::Window>("Terminal", window_size(), icon_path(), style);
|
||||
|
||||
auto& superview = window.create_superview<TerminalView, TerminalViewController>(ptmx);
|
||||
window.set_focused_view(superview);
|
||||
return true;
|
||||
}
|
||||
|
||||
void application_will_terminate() override
|
||||
{
|
||||
std::kill(shell_pid, 9);
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
SET_APP_DELEGATE(AppDelegate);
|
||||
16
userland/applications/terminal/BUILD.gn
Normal file
16
userland/applications/terminal/BUILD.gn
Normal file
@@ -0,0 +1,16 @@
|
||||
import("//build/userland/TEMPLATE.gni")
|
||||
|
||||
xOS_application("terminal") {
|
||||
display_name = "Terminal"
|
||||
sources = [
|
||||
"AppDelegate.cpp",
|
||||
"TerminalView.cpp",
|
||||
]
|
||||
configs = [ "//build/userland:userland_flags" ]
|
||||
deplibs = [
|
||||
"libcxx",
|
||||
"libfoundation",
|
||||
"libg",
|
||||
"libui",
|
||||
]
|
||||
}
|
||||
229
userland/applications/terminal/TerminalView.cpp
Normal file
229
userland/applications/terminal/TerminalView.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
#include "TerminalView.h"
|
||||
#include <algorithm>
|
||||
#include <libfoundation/EventLoop.h>
|
||||
#include <libfoundation/KeyboardMapping.h>
|
||||
#include <libg/Color.h>
|
||||
#include <libui/Context.h>
|
||||
|
||||
TerminalView::TerminalView(UI::View* superview, const LG::Rect& frame, int ptmx)
|
||||
: UI::View(superview, frame)
|
||||
, m_ptmx(ptmx)
|
||||
{
|
||||
recalc_dimensions(frame);
|
||||
}
|
||||
|
||||
TerminalView::TerminalView(UI::View* superview, UI::Window* window, const LG::Rect& frame, int ptmx)
|
||||
: UI::View(superview, window, frame)
|
||||
, m_ptmx(ptmx)
|
||||
{
|
||||
recalc_dimensions(frame);
|
||||
LFoundation::EventLoop::the().add(LFoundation::Timer([this] {
|
||||
this->m_cursor_visible = !this->m_cursor_visible;
|
||||
this->invalidate_cursor_glyph();
|
||||
},
|
||||
400, LFoundation::Timer::Repeat));
|
||||
}
|
||||
|
||||
void TerminalView::recalc_dimensions(const LG::Rect& frame)
|
||||
{
|
||||
m_max_rows = (frame.height() - padding() - UI::SafeArea::Bottom) / glyph_height();
|
||||
m_max_cols = (frame.width() - 2 * padding()) / glyph_width();
|
||||
// FIXME: Add copy and resize on window resize.
|
||||
char* new_data = (char*)malloc(m_max_rows * m_max_cols);
|
||||
memset(new_data, 0, m_max_rows * m_max_cols);
|
||||
if (m_display_data) {
|
||||
free(m_display_data);
|
||||
}
|
||||
m_display_data = new_data;
|
||||
}
|
||||
|
||||
void TerminalView::display(const LG::Rect& rect)
|
||||
{
|
||||
LG::Context ctx = UI::graphics_current_context();
|
||||
ctx.add_clip(rect);
|
||||
|
||||
ctx.set_fill_color(background_color());
|
||||
ctx.fill(bounds());
|
||||
|
||||
ctx.set_fill_color(cursor_color());
|
||||
auto cursor_left_corner = pos_on_screen();
|
||||
ctx.fill(LG::Rect(cursor_left_corner.x(), cursor_left_corner.y(), cursor_width(), glyph_height()));
|
||||
|
||||
auto& f = font();
|
||||
ctx.set_fill_color(font_color());
|
||||
LG::Point<int> text_start { padding(), padding() };
|
||||
|
||||
for (int i = 0; i < m_max_rows; i++) {
|
||||
for (int j = 0; j < m_max_cols; j++) {
|
||||
int idx = i * m_max_cols + j;
|
||||
ctx.draw(text_start, f.glyph(m_display_data[idx]));
|
||||
text_start.offset_by(glyph_width(), 0);
|
||||
}
|
||||
text_start.set_x(padding());
|
||||
text_start.offset_by(0, glyph_height());
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalView::scroll_line()
|
||||
{
|
||||
data_do_new_line();
|
||||
set_needs_display();
|
||||
}
|
||||
|
||||
void TerminalView::data_do_new_line()
|
||||
{
|
||||
char* data_plus_line = m_display_data + (m_max_cols);
|
||||
char* data_end_minus_line = m_display_data + (m_max_rows - 1) * m_max_cols;
|
||||
memmove(m_display_data, data_plus_line, (m_max_rows - 1) * m_max_cols);
|
||||
memset(data_end_minus_line, 0, m_max_cols);
|
||||
}
|
||||
|
||||
WindowStatus TerminalView::cursor_positions_do_new_line()
|
||||
{
|
||||
m_col = 0;
|
||||
m_row++;
|
||||
if (m_row == m_max_rows) {
|
||||
m_row--;
|
||||
return DoNewLine;
|
||||
}
|
||||
return Normal;
|
||||
}
|
||||
|
||||
WindowStatus TerminalView::cursor_position_move_right()
|
||||
{
|
||||
m_col++;
|
||||
if (m_col == m_max_cols) {
|
||||
return cursor_positions_do_new_line();
|
||||
}
|
||||
return Normal;
|
||||
}
|
||||
|
||||
WindowStatus TerminalView::cursor_position_move_left()
|
||||
{
|
||||
m_col--;
|
||||
if (m_col == 0 && m_row > 0) {
|
||||
m_row--;
|
||||
}
|
||||
return Normal;
|
||||
}
|
||||
|
||||
void TerminalView::new_line()
|
||||
{
|
||||
will_move_cursor();
|
||||
WindowStatus status = cursor_positions_do_new_line();
|
||||
switch (status) {
|
||||
case DoNewLine:
|
||||
scroll_line();
|
||||
break;
|
||||
case Normal:
|
||||
break;
|
||||
}
|
||||
did_move_cursor();
|
||||
}
|
||||
|
||||
void TerminalView::increment_counter()
|
||||
{
|
||||
will_move_cursor();
|
||||
m_col++;
|
||||
if (m_col == m_max_cols) {
|
||||
new_line();
|
||||
}
|
||||
did_move_cursor();
|
||||
}
|
||||
|
||||
void TerminalView::decrement_counter()
|
||||
{
|
||||
will_move_cursor();
|
||||
m_col--;
|
||||
if (m_col == 0) {
|
||||
m_row--;
|
||||
}
|
||||
did_move_cursor();
|
||||
}
|
||||
|
||||
void TerminalView::put_char(char c)
|
||||
{
|
||||
auto pt = pos_on_screen();
|
||||
set_needs_display(LG::Rect(pt.x(), pt.y(), glyph_width(), glyph_height()));
|
||||
m_display_data[pos_in_data()] = c;
|
||||
}
|
||||
|
||||
void TerminalView::push_back_char(char c)
|
||||
{
|
||||
if (c == '\n') {
|
||||
new_line();
|
||||
return;
|
||||
}
|
||||
put_char(c);
|
||||
increment_counter();
|
||||
}
|
||||
|
||||
void TerminalView::put_text(const std::string& data)
|
||||
{
|
||||
auto current_pos = pos_on_screen();
|
||||
LG::Point<int> top_left_update_location { current_pos.x(), current_pos.y() };
|
||||
LG::Point<int> bottom_right_update_location { current_pos.x(), current_pos.y() };
|
||||
auto set_to_redraw_full_screen = [&]() {
|
||||
data_do_new_line();
|
||||
top_left_update_location = { bounds().min_x(), bounds().min_y() };
|
||||
bottom_right_update_location = { bounds().max_x(), bounds().max_y() };
|
||||
};
|
||||
|
||||
will_move_cursor();
|
||||
int n = data.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = data[i];
|
||||
if (c == '\n') {
|
||||
auto status = cursor_positions_do_new_line();
|
||||
if (status == DoNewLine) {
|
||||
set_to_redraw_full_screen();
|
||||
}
|
||||
} else {
|
||||
auto pt = pos_on_screen();
|
||||
data_set_char(c);
|
||||
auto status = cursor_position_move_right();
|
||||
if (status == DoNewLine) {
|
||||
set_to_redraw_full_screen();
|
||||
} else {
|
||||
top_left_update_location.set_x(std::min(top_left_update_location.x(), pt.x()));
|
||||
top_left_update_location.set_y(std::min(top_left_update_location.y(), pt.y()));
|
||||
bottom_right_update_location.set_x(std::max(bottom_right_update_location.x(), pt.x() + glyph_width()));
|
||||
bottom_right_update_location.set_y(std::max(bottom_right_update_location.y(), pt.y() + glyph_height()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto w = bottom_right_update_location.x() - top_left_update_location.x() + 1;
|
||||
auto h = bottom_right_update_location.y() - top_left_update_location.y() + 1;
|
||||
set_needs_display(LG::Rect(top_left_update_location.x(), top_left_update_location.y(), w, h));
|
||||
did_move_cursor();
|
||||
}
|
||||
|
||||
void TerminalView::send_input()
|
||||
{
|
||||
write(ptmx(), m_input.c_str(), m_input.size());
|
||||
m_input.clear();
|
||||
}
|
||||
|
||||
void TerminalView::receive_keyup_event(UI::KeyUpEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void TerminalView::receive_keydown_event(UI::KeyDownEvent& event)
|
||||
{
|
||||
// FIXME: More symbols and static size of font
|
||||
if (event.key() == LFoundation::Keycode::KEY_BACKSPACE) {
|
||||
if (m_input.size()) {
|
||||
m_input.pop_back();
|
||||
decrement_counter();
|
||||
put_char(' ');
|
||||
}
|
||||
} else if (event.key() == LFoundation::Keycode::KEY_RETURN) {
|
||||
m_input.push_back('\n');
|
||||
push_back_char('\n');
|
||||
send_input();
|
||||
} else if (event.key() < 128) {
|
||||
m_input.push_back(char(event.key()));
|
||||
push_back_char(char(event.key()));
|
||||
}
|
||||
}
|
||||
84
userland/applications/terminal/TerminalView.h
Normal file
84
userland/applications/terminal/TerminalView.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
#include <libg/Font.h>
|
||||
#include <libui/View.h>
|
||||
#include <string>
|
||||
|
||||
enum WindowStatus {
|
||||
Normal,
|
||||
DoNewLine,
|
||||
};
|
||||
|
||||
class TerminalView : public UI::View {
|
||||
UI_OBJECT();
|
||||
|
||||
public:
|
||||
TerminalView(UI::View* superview, const LG::Rect&, int ptmx);
|
||||
TerminalView(UI::View* superview, UI::Window* window, const LG::Rect&, int ptmx);
|
||||
|
||||
const LG::Color& font_color() const { return m_font_color; }
|
||||
const LG::Color cursor_color() const { return m_cursor_visible ? LG::Color(80, 80, 80, 255) : background_color(); }
|
||||
const LG::Color& background_color() const { return m_background_color; }
|
||||
inline const LG::Font& font() const { return *m_font_ptr; }
|
||||
|
||||
inline int glyph_width() const { return font().glyph('.').width(); }
|
||||
inline int glyph_height() const { return font().size() + 2; }
|
||||
|
||||
inline LG::Point<int> pos_on_screen() const { return { (int)m_col * glyph_width() + padding(), (int)m_row * glyph_height() + padding() }; }
|
||||
inline int pos_in_data() const { return m_max_cols * m_row + m_col; }
|
||||
|
||||
void put_char(char c);
|
||||
void put_text(const std::string& data);
|
||||
|
||||
void display(const LG::Rect& rect) override;
|
||||
void receive_keyup_event(UI::KeyUpEvent&) override;
|
||||
void receive_keydown_event(UI::KeyDownEvent&) override;
|
||||
|
||||
int ptmx() const { return m_ptmx; }
|
||||
|
||||
private:
|
||||
void terminal_init();
|
||||
|
||||
WindowStatus cursor_positions_do_new_line();
|
||||
WindowStatus cursor_position_move_right();
|
||||
WindowStatus cursor_position_move_left();
|
||||
void data_do_new_line();
|
||||
inline void data_set_char(char c)
|
||||
{
|
||||
m_display_data[pos_in_data()] = c;
|
||||
}
|
||||
|
||||
void scroll_line();
|
||||
void new_line();
|
||||
void increment_counter();
|
||||
void decrement_counter();
|
||||
|
||||
void recalc_dimensions(const LG::Rect&);
|
||||
void push_back_char(char c);
|
||||
void send_input();
|
||||
|
||||
inline void invalidate_cursor_glyph()
|
||||
{
|
||||
auto pt = pos_on_screen();
|
||||
set_needs_display(LG::Rect(pt.x(), pt.y(), cursor_width() + spacing(), glyph_height()));
|
||||
}
|
||||
inline void will_move_cursor() { invalidate_cursor_glyph(); }
|
||||
inline void did_move_cursor() { invalidate_cursor_glyph(); }
|
||||
|
||||
constexpr int padding() const { return 2; }
|
||||
constexpr int spacing() const { return 2; }
|
||||
constexpr int cursor_width() const { return 5; }
|
||||
|
||||
int m_ptmx { -1 };
|
||||
std::string m_input {};
|
||||
|
||||
bool m_cursor_visible { true };
|
||||
LG::Color m_background_color { LG::Color(47, 47, 53) };
|
||||
LG::Color m_font_color { LG::Color::LightSystemText };
|
||||
LG::Font* m_font_ptr { LG::Font::load_from_file("/res/fonts/Liza.font/10/regular.font") };
|
||||
|
||||
size_t m_max_cols { 0 };
|
||||
size_t m_max_rows { 0 };
|
||||
size_t m_col { 0 };
|
||||
size_t m_row { 0 };
|
||||
char* m_display_data { nullptr };
|
||||
};
|
||||
34
userland/applications/terminal/TerminalViewController.h
Normal file
34
userland/applications/terminal/TerminalViewController.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "TerminalView.h"
|
||||
#include <libui/ViewController.h>
|
||||
#include <memory>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class TerminalViewController : public UI::ViewController<TerminalView> {
|
||||
public:
|
||||
TerminalViewController(TerminalView& view)
|
||||
: UI::ViewController<TerminalView>(view)
|
||||
{
|
||||
}
|
||||
virtual ~TerminalViewController() = default;
|
||||
|
||||
void init_listners()
|
||||
{
|
||||
LFoundation::EventLoop::the().add(
|
||||
view().ptmx(), [this] {
|
||||
char text[256];
|
||||
int cnt = read(view().ptmx(), text, 255);
|
||||
text[cnt] = '\0';
|
||||
view().put_text(std::string(text, cnt));
|
||||
},
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void view_did_load() override
|
||||
{
|
||||
init_listners();
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
Reference in New Issue
Block a user