Explorar o código

[UI] TurboVision added via FFI for UI purposes

Slava Barinov %!s(int64=4) %!d(string=hai) anos
pai
achega
1348304bf1
Modificáronse 8 ficheiros con 188 adicións e 17 borrados
  1. 28 17
      .github/workflows/rust.yml
  2. 3 0
      .gitmodules
  3. 3 0
      Cargo.toml
  4. 48 0
      build.rs
  5. 1 0
      extern/tvision
  6. 89 0
      extern/ui.cpp
  7. 1 0
      src/main.rs
  8. 15 0
      src/ui.rs

+ 28 - 17
.github/workflows/rust.yml

@@ -13,43 +13,54 @@ jobs:
           - nightly
 
     steps:
-      - uses: actions/checkout@v1
+      - name: Checkout repository and submodules
+        uses: actions/checkout@v2
+        with:
+          submodules: recursive
+
+      - name: Install dependencies
+        run: "sudo apt-get install libgpm-dev libncurses5-dev cmake"
 
-      - uses: actions-rs/toolchain@v1
+      - name: Install toolchain
+        uses: actions-rs/toolchain@v1
         with:
           profile: minimal
           toolchain: ${{ matrix.rust }}
           override: true
           components: rustfmt, clippy
 
-      - uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --release
-
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --release
-
-      - uses: actions-rs/cargo@v1
+      - name: Check formatting
+        uses: actions-rs/cargo@v1
         with:
           command: fmt
           args: --all -- --check
 
-      - uses: actions-rs/cargo@v1
+      - name: Run static analyzer
+        uses: actions-rs/cargo@v1
         with:
           command: clippy
           args: -- -D warnings
 
-      - name: Run cargo-tarpaulin
+      - name: Build release version
+        uses: actions-rs/cargo@v1
+        with:
+          command: build
+          args: --release
+
+      - name: Run tests
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --release
+
+      - name: Collect test coverage
         uses: actions-rs/tarpaulin@v0.1
         if: ${{ matrix.rust == 'stable' }}
         with:
-          version: '0.15.0'
+          version: '0.16.0'
           out-type: Xml
           run-types: 'Tests'
-          args: '-- --test-threads 1'
+          args: '--force-clean -- --test-threads 1'
 
       - name: Upload to codecov.io
         uses: codecov/codecov-action@v1.0.2

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "extern/tvision"]
+	path = extern/tvision
+	url = https://github.com/magiblot/tvision.git

+ 3 - 0
Cargo.toml

@@ -16,3 +16,6 @@ shellexpand = "2.1"
 radix_trie = { version = "0.2", features = ["serde"] }
 libc = "0.2"
 
+[build-dependencies]
+cc = "1.0"
+pkg-config = "0.3"

+ 48 - 0
build.rs

@@ -0,0 +1,48 @@
+use cc::Build;
+use pkg_config::Config;
+use std::env;
+use std::process::Command;
+
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-changed=extern/ui.cpp");
+    println!("cargo:rerun-if-changed=extern/tvision");
+
+    Command::new("cmake")
+        .args(&[
+            "extern/tvision",
+            "-B",
+            "extern/tvision/build",
+            "-DCMAKE_C_FLAGS=-fPIC",
+            "-DCMAKE_CXX_FLAGS=-fPIC",
+            "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
+            "-DTV_BUILD_EXAMPLES=off",
+        ])
+        .status()
+        .unwrap();
+
+    let jobs = env::var("NUM_JOBS").unwrap();
+
+    Command::new("cmake")
+        .args(&["--build", "extern/tvision/build", "--parallel", &jobs])
+        .status()
+        .unwrap();
+
+    println!("cargo:rustc-link-search=extern/tvision/build");
+
+    Build::new()
+        .cpp(true)
+        .file("extern/ui.cpp")
+        .flag("-Wno-unknown-pragmas")
+        .flag("-Wno-reorder")
+        .include("extern/tvision/include")
+        .compile("libui.a");
+
+    println!("cargo:rustc-link-lib=tvision");
+    println!("cargo:rustc-link-lib=gpm");
+    Config::new()
+        .atleast_version("5.9")
+        .statik(true)
+        .probe("ncurses")
+        .unwrap();
+}

+ 1 - 0
extern/tvision

@@ -0,0 +1 @@
+Subproject commit 1e8903542eb09d7a10ac313ca358ba58667cbe61

+ 89 - 0
extern/ui.cpp

@@ -0,0 +1,89 @@
+#define Uses_TKeys
+#define Uses_TApplication
+#define Uses_TEvent
+#define Uses_TRect
+#define Uses_TDialog
+#define Uses_TStaticText
+#define Uses_TButton
+#define Uses_TMenuBar
+#define Uses_TSubMenu
+#define Uses_TMenuItem
+#define Uses_TStatusLine
+#define Uses_TStatusItem
+#define Uses_TStatusDef
+#define Uses_TDeskTop
+#include <string>
+#include <tvision/tv.h>
+
+const int GreetThemCmd = 100;
+
+class THelloApp : public TApplication {
+
+public:
+  THelloApp();
+
+  virtual void handleEvent(TEvent &event);
+  static TMenuBar *initMenuBar(TRect);
+  static TStatusLine *initStatusLine(TRect);
+  void set_hello(const std::string &new_line) { hello_line = new_line; }
+
+private:
+  std::string hello_line;
+  void greetingBox();
+};
+
+THelloApp::THelloApp()
+    : TProgInit(&THelloApp::initStatusLine, &THelloApp::initMenuBar,
+                &THelloApp::initDeskTop) {}
+
+void THelloApp::greetingBox() {
+  TDialog *d = new TDialog(TRect(25, 5, 55, 16), "Hello, World!");
+
+  d->insert(new TStaticText(TRect(3, 5, 15, 6), hello_line.c_str()));
+  d->insert(new TButton(TRect(16, 2, 28, 4), "Terrific", cmCancel, bfNormal));
+  d->insert(new TButton(TRect(16, 4, 28, 6), "Ok", cmCancel, bfNormal));
+  d->insert(new TButton(TRect(16, 6, 28, 8), "Lousy", cmCancel, bfNormal));
+  d->insert(new TButton(TRect(16, 8, 28, 10), "Cancel", cmCancel, bfNormal));
+
+  deskTop->execView(d);
+  destroy(d);
+}
+
+void THelloApp::handleEvent(TEvent &event) {
+  TApplication::handleEvent(event);
+  if (event.what == evCommand) {
+    switch (event.message.command) {
+    case GreetThemCmd:
+      greetingBox();
+      clearEvent(event);
+      break;
+    default:
+      break;
+    }
+  }
+}
+
+TMenuBar *THelloApp::initMenuBar(TRect r) {
+
+  r.b.y = r.a.y + 1;
+
+  return new TMenuBar(
+      r, *new TSubMenu("~F~ile", kbAltH) +
+             *new TMenuItem("~G~reeting...", GreetThemCmd, kbAltG) + newLine() +
+             *new TMenuItem("E~x~it", cmQuit, cmQuit, hcNoContext, "Alt-X"));
+}
+
+TStatusLine *THelloApp::initStatusLine(TRect r) {
+  r.a.y = r.b.y - 1;
+  return new TStatusLine(r,
+                         *new TStatusDef(0, 0xFFFF) +
+                             *new TStatusItem("~Alt-X~ Exit", kbAltX, cmQuit) +
+                             *new TStatusItem(0, kbF10, cmMenu));
+}
+
+extern "C" int ui_main(char *hello_line) {
+  THelloApp helloWorld;
+  helloWorld.set_hello(hello_line);
+  helloWorld.run();
+  return 0;
+}

+ 1 - 0
src/main.rs

@@ -142,4 +142,5 @@ fn main() {
 
     db.set("catmap", &catmap).unwrap();
     db.dump().unwrap();
+    ui::run_tv();
 }

+ 15 - 0
src/ui.rs

@@ -1,4 +1,19 @@
+use std::ffi::CString;
 use std::io::{stdin, stdout, Write};
+use std::os::raw::c_char;
+
+extern "C" {
+    fn ui_main(line: *const c_char);
+}
+
+#[cfg_attr(tarpaulin, ignore)]
+pub fn run_tv() {
+    let line = CString::new("I'm calling TV!").expect("Failed to create string");
+    unsafe {
+        ui_main(line.as_ptr());
+    }
+    println!("Hello, world!");
+}
 
 pub fn input_category(item: &str) -> String {
     let mut x = String::with_capacity(64);