From bb4d06a79eaa2b31ad7917a4a51c3a2c559cbfc0 Mon Sep 17 00:00:00 2001
From: jiande <jiande2020@protonmail.com>
Date: Wed, 28 Sep 2022 11:52:00 +0800
Subject: [PATCH 1/2] Add new features: Overlay

---
 CMakeLists.txt                        |   1 +
 src/ui/panel/overlay/overlay_impl.cpp | 283 ++++++++++++++++++++++++++
 src/ui/panel/panel.hpp                |   1 +
 src/ui/ui.cpp                         |   1 +
 4 files changed, 286 insertions(+)
 create mode 100644 src/ui/panel/overlay/overlay_impl.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ae3934f..438a574 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,6 +40,7 @@ add_executable(${PROJECT_NAME}
   src/ui/panel/passwd/passwd.cpp
   src/ui/panel/ssh/ssh.cpp
   src/ui/panel/service/service_impl.cpp
+  src/ui/panel/overlay/overlay_impl.cpp
   src/ui/ui.cpp
   src/ui/ui.hpp
   src/utils.hpp
diff --git a/src/ui/panel/overlay/overlay_impl.cpp b/src/ui/panel/overlay/overlay_impl.cpp
new file mode 100644
index 0000000..e7acead
--- /dev/null
+++ b/src/ui/panel/overlay/overlay_impl.cpp
@@ -0,0 +1,283 @@
+#include "ftxui/component/component.hpp"
+#include "ui/panel/panel.hpp"
+#include "utils.hpp"
+
+#include <array>
+#include <cstdio>
+#include <filesystem>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+using namespace ftxui;
+
+namespace ui {
+
+namespace {
+
+class Overlay : public ComponentBase {
+ public:
+  Overlay(std::vector<std::string>* overlay,
+          int pos,
+          int* selected,
+          bool* checked)
+      : overlays_(overlay), pos_(pos), selected_(selected), checked_(checked) {
+    Add(Container::Horizontal({
+        checkBox_,
+        dropDown_,
+    }));
+  }
+
+  ~Overlay() = default;
+
+ private:
+  std::vector<std::string>* overlays_;
+  int pos_;
+  int* selected_;
+  bool* checked_;
+  Component dropDown_ = Dropdown(overlays_, selected_);
+  Component checkBox_ =
+      Checkbox("Overlay " + std::to_string(pos_) + " : ", checked_);
+
+  Element Render() override {
+    return hbox({
+        checkBox_->Render() | vcenter,
+        dropDown_->Render(),
+    });
+  }
+};
+
+class overlayImpl : public PanelBase {
+ public:
+  overlayImpl() {
+    get_overlays();
+    check_uEnv();
+    build_UI();
+
+    Add(Container::Vertical({
+        container_,
+        button_,
+    }));
+  }
+
+  ~overlayImpl() = default;
+
+  std::string Title() override { return "Overlay"; }
+
+ private:
+  void get_overlays() {
+    overlays_.clear();
+    const std::string path_version = "/proc/version";
+    std::string line;
+
+    std::ifstream versionFile(path_version);
+    versionFile >> line;
+    versionFile >> line;
+    versionFile >> kernel_version;
+    versionFile.close();
+
+    std::string overlay_path = "/boot/dtbs/" + kernel_version + "/overlays";
+
+    overlays_.push_back("<fileX>.dtbo");
+
+    for (const auto& file : std::filesystem::directory_iterator(overlay_path)) {
+      std::stringstream ss(file.path());
+
+      while (getline(ss, line, '/'))
+        ;
+
+      overlays_.push_back(line);
+    }
+  }
+
+  void build_UI() {
+    for (int i = 0; i < (int)drop_selected_.size(); i++) {
+      container_->Add(
+          Make<Overlay>(&overlays_, i, &drop_selected_[i], &box_checked_[i]));
+    }
+
+    tab_->Add(container_);
+    tab_->Add(Container::Vertical({}));
+  }
+
+  void no_overlap() {
+    for (int i = 0; i < (int)drop_selected_.size(); i++) {
+      if (drop_selected_[i] == 0)
+        box_checked_[i] = false;
+
+      if (i == conSelected_)
+        continue;
+
+      if (drop_selected_[conSelected_] == drop_selected_[i]) {
+        drop_selected_[conSelected_] = 0;
+      }
+    }
+  }
+
+  void check_uEnv() {
+    std::ifstream infile;
+    infile.open(File_uEnv);
+    std::string lines;
+
+    if (!infile) {
+      tabSelected_ = 1;
+    }
+
+    while (getline(infile, lines)) {
+      if (!lines.compare("###Overide capes with eeprom")) {
+        for (int i = 0; i < 4; i++) {
+          getline(infile, lines);
+          std::stringstream ss(lines);
+          std::string temp, dtbo;
+
+          getline(ss, temp, '=');
+          getline(ss, dtbo, '=');
+
+          if (!temp.compare("#uboot_overlay_addr" + std::to_string(i))) {
+            box_checked_[i] = false;
+
+            for (int j = 0; j < (int)overlays_.size(); j++) {
+              if (!overlays_[j].compare(dtbo)) {
+                drop_selected_[i] = j;
+              }
+            }
+          } else if (!temp.compare("uboot_overlay_addr" + std::to_string(i))) {
+            box_checked_[i] = true;
+
+            for (int j = 0; j < (int)overlays_.size(); j++) {
+              if (!overlays_[j].compare(dtbo)) {
+                drop_selected_[i] = j;
+              }
+            }
+
+          } else {
+            box_checked_[i] = false;
+          }
+        }
+      }
+
+      if (!lines.compare("###Additional custom capes")) {
+        for (int i = 4; i < 8; i++) {
+          getline(infile, lines);
+          std::stringstream ss(lines);
+          std::string temp, dtbo;
+
+          getline(ss, temp, '=');
+          getline(ss, dtbo, '=');
+
+          if (!temp.compare("#uboot_overlay_addr" + std::to_string(i))) {
+            box_checked_[i] = false;
+
+            for (int j = 0; j < (int)overlays_.size(); j++) {
+              if (!overlays_[j].compare(dtbo)) {
+                drop_selected_[i] = j;
+              }
+            }
+          } else if (!temp.compare("uboot_overlay_addr" + std::to_string(i))) {
+            box_checked_[i] = true;
+
+            for (int j = 0; j < (int)overlays_.size(); j++) {
+              if (!overlays_[j].compare(dtbo)) {
+                drop_selected_[i] = j;
+              }
+            }
+
+          } else {
+            box_checked_[i] = false;
+          }
+        }
+      }
+    }
+    infile.close();
+  }
+
+  void overwrite_uEnv() {
+    std::ifstream infile;
+    std::ofstream outfile;
+
+    infile.open(File_uEnv);
+    outfile.open(File_Backup);
+
+    std::string lines;
+
+    while (getline(infile, lines)) {
+      if (!lines.compare("###Overide capes with eeprom")) {
+        outfile << lines << std::endl;
+        for (int i = 0; i < 4; i++) {
+          getline(infile, lines);
+          if (box_checked_[i])
+            outfile << "uboot_overlay_addr" << i << "="
+                    << overlays_[drop_selected_[i]] << std::endl;
+          else
+            outfile << "#uboot_overlay_addr" << i << "="
+                    << overlays_[drop_selected_[i]] << std::endl;
+        }
+        continue;
+      }
+
+      if (!lines.compare("###Additional custom capes")) {
+        outfile << lines << std::endl;
+        for (int i = 4; i < 8; i++) {
+          getline(infile, lines);
+          if (box_checked_[i])
+            outfile << "uboot_overlay_addr" << i << "="
+                    << overlays_[drop_selected_[i]] << std::endl;
+          else
+            outfile << "#uboot_overlay_addr" << i << "="
+                    << overlays_[drop_selected_[i]] << std::endl;
+        }
+        continue;
+      }
+
+      outfile << lines << std::endl;
+    }
+
+    infile.close();
+    outfile.close();
+
+    std::rename(File_Backup.c_str(), File_uEnv.c_str());
+  }
+
+  Element Render() override {
+    no_overlap();
+
+    Element content = vbox({
+        text("Kernel Version : " + kernel_version),
+        text("Currently only support maximum 8 overlays") | color(Color::Red),
+        separator(),
+        container_->Render() | flex | frame | vscroll_indicator,
+        separator(),
+        button_->Render(),
+    });
+
+    Element error =
+        vbox({text("Features not support!") | color(Color::Red) | bold});
+
+    return (tabSelected_ == 0) ? content : error;
+  }
+
+  int conSelected_ = 0;
+  int tabSelected_ = 0;
+  std::string kernel_version;
+  const std::string File_uEnv = "/boot/uEnv.txt";
+  const std::string File_Backup = "./backup.txt";
+  std::vector<std::string> overlays_;
+  std::array<int, 8> drop_selected_ = {0, 0, 0, 0, 0, 0, 0, 0};
+  std::array<bool, 8> box_checked_ = {false, false, false, false,
+                                      false, false, false, false};
+  Component tab_ = Container::Vertical({}, &tabSelected_);
+  Component container_ = Container::Vertical({}, &conSelected_);
+  Component button_ = Button("Apply", [this] { overwrite_uEnv(); });
+};
+
+}  // namespace
+
+namespace panel {
+Panel overlay() {
+  return Make<overlayImpl>();
+}
+
+}  // namespace panel
+
+}  // namespace ui
\ No newline at end of file
diff --git a/src/ui/panel/panel.hpp b/src/ui/panel/panel.hpp
index e03fa11..efc7a71 100644
--- a/src/ui/panel/panel.hpp
+++ b/src/ui/panel/panel.hpp
@@ -34,6 +34,7 @@ Panel PinMux();
 Panel About();
 Panel passwd();
 Panel ssh();
+Panel overlay();
 }  // namespace panel
 }  // namespace ui
 
diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp
index 30bdaf5..b5a1a28 100644
--- a/src/ui/ui.cpp
+++ b/src/ui/ui.cpp
@@ -184,6 +184,7 @@ void Loop() {
            panel::PinMux(),
            panel::service(&screen),
            panel::ADC(&screen),
+           panel::overlay(),
        }},
       {"Network",
        {
-- 
GitLab


From 769ffd8774c0a7607985a98563a43a09831e26f6 Mon Sep 17 00:00:00 2001
From: jiande <jiande2020@protonmail.com>
Date: Wed, 28 Sep 2022 05:26:17 +0000
Subject: [PATCH 2/2] overlay: add comment and do clang format

---
 src/ui/panel/overlay/overlay_impl.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/ui/panel/overlay/overlay_impl.cpp b/src/ui/panel/overlay/overlay_impl.cpp
index e7acead..69a7d6b 100644
--- a/src/ui/panel/overlay/overlay_impl.cpp
+++ b/src/ui/panel/overlay/overlay_impl.cpp
@@ -16,6 +16,7 @@ namespace ui {
 
 namespace {
 
+/* Handle overlay component with checkbox, title and dropbox */
 class Overlay : public ComponentBase {
  public:
   Overlay(std::vector<std::string>* overlay,
@@ -66,6 +67,7 @@ class overlayImpl : public PanelBase {
   std::string Title() override { return "Overlay"; }
 
  private:
+  /* Scan all the dtbo file in /boot/dtbs and store in vector */
   void get_overlays() {
     overlays_.clear();
     const std::string path_version = "/proc/version";
@@ -91,16 +93,22 @@ class overlayImpl : public PanelBase {
     }
   }
 
+  /* Build Overlay and Tab Component */
   void build_UI() {
+    // Create Overlay Component
     for (int i = 0; i < (int)drop_selected_.size(); i++) {
       container_->Add(
           Make<Overlay>(&overlays_, i, &drop_selected_[i], &box_checked_[i]));
     }
 
+    // Create Tab Component
     tab_->Add(container_);
     tab_->Add(Container::Vertical({}));
   }
 
+  /* Handle if overlay selected twice             */
+  /* If overlay choosed it will set to empty file */
+  /* If overlay file not selected can't enable it */
   void no_overlap() {
     for (int i = 0; i < (int)drop_selected_.size(); i++) {
       if (drop_selected_[i] == 0)
@@ -115,6 +123,7 @@ class overlayImpl : public PanelBase {
     }
   }
 
+  /* Read file uEnv and update in BB-Config */
   void check_uEnv() {
     std::ifstream infile;
     infile.open(File_uEnv);
@@ -192,6 +201,7 @@ class overlayImpl : public PanelBase {
     infile.close();
   }
 
+  /* Apply changes by updating uEnv.txt file */
   void overwrite_uEnv() {
     std::ifstream infile;
     std::ofstream outfile;
@@ -236,6 +246,7 @@ class overlayImpl : public PanelBase {
     infile.close();
     outfile.close();
 
+    // Replace old file with new file
     std::rename(File_Backup.c_str(), File_uEnv.c_str());
   }
 
@@ -254,6 +265,7 @@ class overlayImpl : public PanelBase {
     Element error =
         vbox({text("Features not support!") | color(Color::Red) | bold});
 
+    // Check if tabSelected == 0 return content page
     return (tabSelected_ == 0) ? content : error;
   }
 
-- 
GitLab