mirror of
https://github.com/m1ngsama/TUT.git
synced 2025-12-24 10:51:46 +00:00
Merge pull request #4 from m1ngsama/feature/ascii-art-tui
feat: Add ASCII art and ANSI shadow effects to TUI
This commit is contained in:
commit
6b433e530d
3 changed files with 182 additions and 12 deletions
|
|
@ -2,6 +2,8 @@
|
||||||
#include "calendar.h"
|
#include "calendar.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
display_splash_screen(); // Display splash screen at startup
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int choice = run_portal_tui();
|
int choice = run_portal_tui();
|
||||||
|
|
||||||
|
|
|
||||||
189
src/tui_view.cpp
189
src/tui_view.cpp
|
|
@ -7,9 +7,29 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <thread> // Added this line
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Define color pairs
|
||||||
|
enum ColorPairs {
|
||||||
|
NORMAL_TEXT = 1,
|
||||||
|
SHADOW_TEXT,
|
||||||
|
BANNER_TEXT,
|
||||||
|
SELECTED_ITEM
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_colors() {
|
||||||
|
if (has_colors()) {
|
||||||
|
start_color();
|
||||||
|
use_default_colors(); // Use terminal's default background
|
||||||
|
init_pair(NORMAL_TEXT, COLOR_WHITE, -1); // White foreground, default background
|
||||||
|
init_pair(SHADOW_TEXT, COLOR_BLACK, -1); // Black foreground, default background (for shadow effect)
|
||||||
|
init_pair(BANNER_TEXT, COLOR_CYAN, -1); // Cyan foreground, default background
|
||||||
|
init_pair(SELECTED_ITEM, COLOR_YELLOW, -1); // Yellow foreground, default background
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string format_date(const std::chrono::system_clock::time_point &tp) {
|
std::string format_date(const std::chrono::system_clock::time_point &tp) {
|
||||||
auto tt = std::chrono::system_clock::to_time_t(tp);
|
auto tt = std::chrono::system_clock::to_time_t(tp);
|
||||||
std::tm tm{};
|
std::tm tm{};
|
||||||
|
|
@ -30,6 +50,7 @@ void run_tui(const std::vector<IcsEvent> &events) {
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
|
|
||||||
initscr();
|
initscr();
|
||||||
|
init_colors(); // Initialize colors
|
||||||
cbreak();
|
cbreak();
|
||||||
noecho();
|
noecho();
|
||||||
keypad(stdscr, TRUE);
|
keypad(stdscr, TRUE);
|
||||||
|
|
@ -41,7 +62,9 @@ void run_tui(const std::vector<IcsEvent> &events) {
|
||||||
// 如果没有任何事件,给出提示信息
|
// 如果没有任何事件,给出提示信息
|
||||||
if (events.empty()) {
|
if (events.empty()) {
|
||||||
clear();
|
clear();
|
||||||
|
attron(COLOR_PAIR(BANNER_TEXT));
|
||||||
mvprintw(0, 0, "NBTCA 未来一个月活动");
|
mvprintw(0, 0, "NBTCA 未来一个月活动");
|
||||||
|
attroff(COLOR_PAIR(BANNER_TEXT));
|
||||||
mvprintw(2, 0, "未来一个月内暂无活动。");
|
mvprintw(2, 0, "未来一个月内暂无活动。");
|
||||||
mvprintw(4, 0, "按任意键退出...");
|
mvprintw(4, 0, "按任意键退出...");
|
||||||
refresh();
|
refresh();
|
||||||
|
|
@ -55,9 +78,44 @@ void run_tui(const std::vector<IcsEvent> &events) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
clear();
|
clear();
|
||||||
mvprintw(0, 0, "NBTCA 未来一个月活动 (q 退出, ↑↓ 滚动)");
|
|
||||||
|
|
||||||
int visibleLines = height - 2;
|
// ASCII art banner for "CALENDAR"
|
||||||
|
std::string calendar_banner[] = {
|
||||||
|
" ██████╗ █████╗ ██╗ ███████╗███╗ ██╗██████╗ █████╗ ██████╗ ",
|
||||||
|
"██╔════╝██╔══██╗██║ ██╔════╝████╗ ██║██╔══██╗██╔══██╗██╔══██╗",
|
||||||
|
"██║ ███████║██║ █████╗ ██╔██╗ ██║██║ ██║███████║██████╔╝",
|
||||||
|
"██║ ██╔══██║██║ ██╔══╝ ██║╚██╗██║██║ ██║██╔══██║██╔══██╗",
|
||||||
|
"╚██████╗██║ ██║███████╗███████╗██║ ╚████║██████╔╝██║ ██║██║ ██║",
|
||||||
|
" ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝╚╝ ╚═╝"
|
||||||
|
};
|
||||||
|
|
||||||
|
int banner_height = sizeof(calendar_banner) / sizeof(calendar_banner[0]);
|
||||||
|
int banner_width = calendar_banner[0].length();
|
||||||
|
|
||||||
|
int start_col_banner = (width - banner_width) / 2;
|
||||||
|
if (start_col_banner < 0) start_col_banner = 0;
|
||||||
|
|
||||||
|
// Draw shadow
|
||||||
|
attron(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
for (int i = 0; i < banner_height; ++i) {
|
||||||
|
mvprintw(i + 1, start_col_banner + 1, "%s", calendar_banner[i].c_str());
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
|
||||||
|
// Draw main banner
|
||||||
|
attron(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
for (int i = 0; i < banner_height; ++i) {
|
||||||
|
mvprintw(i, start_col_banner, "%s", calendar_banner[i].c_str());
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
std::string instruction_msg = "(q 退出, ↑↓ 滚动)";
|
||||||
|
mvprintw(banner_height + 1, (width - instruction_msg.length()) / 2, "%s", instruction_msg.c_str());
|
||||||
|
attroff(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
|
||||||
|
int start_event_row = banner_height + 3; // Start events below the banner and instruction
|
||||||
|
int visibleLines = height - start_event_row - 1; // Adjust visible lines
|
||||||
|
|
||||||
if (selected < top) {
|
if (selected < top) {
|
||||||
top = selected;
|
top = selected;
|
||||||
|
|
@ -80,11 +138,19 @@ void run_tui(const std::vector<IcsEvent> &events) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx == selected) {
|
if (idx == selected) {
|
||||||
attron(A_REVERSE);
|
attron(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
mvprintw(i + 1, 0, "%s", line.c_str());
|
mvprintw(start_event_row + i, 0, "%s", line.c_str());
|
||||||
attroff(A_REVERSE);
|
attroff(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
} else {
|
} else {
|
||||||
mvprintw(i + 1, 0, "%s", line.c_str());
|
attron(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
mvprintw(start_event_row + i, 0, "%s", line.c_str());
|
||||||
|
attroff(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
}
|
||||||
|
// Add a separator after each event
|
||||||
|
if (i < visibleLines - 1 && idx + 1 < static_cast<int>(events.size())) {
|
||||||
|
attron(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
mvprintw(start_event_row + i + 1, 0, "%s", std::string(width, '-').c_str()); // Dynamic separator
|
||||||
|
attroff(COLOR_PAIR(SHADOW_TEXT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,27 +173,68 @@ int run_portal_tui() {
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
|
|
||||||
initscr();
|
initscr();
|
||||||
|
init_colors(); // Initialize colors
|
||||||
cbreak();
|
cbreak();
|
||||||
noecho();
|
noecho();
|
||||||
keypad(stdscr, TRUE);
|
keypad(stdscr, TRUE);
|
||||||
curs_set(0);
|
curs_set(0);
|
||||||
|
|
||||||
|
int height, width;
|
||||||
|
getmaxyx(stdscr, height, width);
|
||||||
|
|
||||||
std::vector<std::string> menu_items = {"Calendar", "Exit"};
|
std::vector<std::string> menu_items = {"Calendar", "Exit"};
|
||||||
int selected = 0;
|
int selected = 0;
|
||||||
int choice = -1;
|
int choice = -1;
|
||||||
|
|
||||||
while (choice == -1) {
|
while (choice == -1) {
|
||||||
clear();
|
clear();
|
||||||
mvprintw(0, 0, "TUT - Feature Portal (q or Enter to select)");
|
|
||||||
|
// ASCII art banner for "NBTCA Tools"
|
||||||
|
std::string banner_art[] = {
|
||||||
|
"███╗ ██╗██████╗ ████████╗ ██████╗ █████╗ ████████╗ ██████╗ ██████╗ ██╗ ███████╗",
|
||||||
|
"████╗ ██║██╔══██╗╚══██╔══╝██╔════╝██╔══██╗ ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██╔════╝",
|
||||||
|
"██╔██╗ ██║██████╔╝ ██║ ██║ ███████║ ██║ ██║ ██║██║ ██║██║ ███████╗",
|
||||||
|
"██║╚██╗██║██╔══██╗ ██║ ██║ ██╔══██║ ██║ ██║ ██║██║ ██║██║ ╚════██║",
|
||||||
|
"██║ ╚████║██████╔╝ ██║ ╚██████╗██║ ██║ ██║ ╚██████╔╝╚██████╔╝███████╗███████║",
|
||||||
|
"╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝"
|
||||||
|
};
|
||||||
|
|
||||||
|
int banner_height = sizeof(banner_art) / sizeof(banner_art[0]);
|
||||||
|
int banner_width = banner_art[0].length();
|
||||||
|
|
||||||
|
int start_col_banner = (width - banner_width) / 2;
|
||||||
|
if (start_col_banner < 0) start_col_banner = 0;
|
||||||
|
|
||||||
|
// Draw shadow
|
||||||
|
attron(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
for (int i = 0; i < banner_height; ++i) {
|
||||||
|
mvprintw(i + 1, start_col_banner + 1, "%s", banner_art[i].c_str());
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
|
||||||
|
// Draw main banner
|
||||||
|
attron(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
for (int i = 0; i < banner_height; ++i) {
|
||||||
|
mvprintw(i, start_col_banner, "%s", banner_art[i].c_str());
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
// Feature Portal message below the banner
|
||||||
|
std::string portal_msg = "Feature Portal (q or Enter to select)";
|
||||||
|
mvprintw(banner_height + 1, (width - portal_msg.length()) / 2, "%s", portal_msg.c_str());
|
||||||
|
attroff(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
|
||||||
for (size_t i = 0; i < menu_items.size(); ++i) {
|
for (size_t i = 0; i < menu_items.size(); ++i) {
|
||||||
if ((int)i == selected) {
|
if ((int)i == selected) {
|
||||||
attron(A_REVERSE);
|
attron(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
}
|
} else {
|
||||||
mvprintw(i + 2, 2, "%s", menu_items[i].c_str());
|
attron(COLOR_PAIR(NORMAL_TEXT));
|
||||||
if ((int)i == selected) {
|
|
||||||
attroff(A_REVERSE);
|
|
||||||
}
|
}
|
||||||
|
// Adjust vertical position based on banner height and portal message
|
||||||
|
mvprintw(banner_height + 3 + i, 2, "%s", menu_items[i].c_str());
|
||||||
|
attroff(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
|
attroff(COLOR_PAIR(NORMAL_TEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|
@ -160,4 +267,62 @@ int run_portal_tui() {
|
||||||
return choice;
|
return choice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 显示启动画面
|
||||||
|
void display_splash_screen() {
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
initscr();
|
||||||
|
init_colors(); // Initialize colors
|
||||||
|
cbreak();
|
||||||
|
noecho();
|
||||||
|
curs_set(0);
|
||||||
|
|
||||||
|
int height, width;
|
||||||
|
getmaxyx(stdscr, height, width);
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
// Simple ASCII art for "NBTCA Tools"
|
||||||
|
std::string splash_art[] = {
|
||||||
|
"███╗ ██╗██████╗ ████████╗ ██████╗ █████╗ ████████╗ ██████╗ ██████╗ ██╗ ███████╗",
|
||||||
|
"████╗ ██║██╔══██╗╚══██╔══╝██╔════╝██╔══██╗ ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██╔════╝",
|
||||||
|
"██╔██╗ ██║██████╔╝ ██║ ██║ ███████║ ██║ ██║ ██║██║ ██║██║ ███████╗",
|
||||||
|
"██║╚██╗██║██╔══██╗ ██║ ██║ ██╔══██║ ██║ ██║ ██║██║ ██║██║ ╚════██║",
|
||||||
|
"██║ ╚████║██████╔╝ ██║ ╚██████╗██║ ██║ ██║ ╚██████╔╝╚██████╔╝███████╗███████║",
|
||||||
|
"╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝"
|
||||||
|
};
|
||||||
|
|
||||||
|
int art_height = sizeof(splash_art) / sizeof(splash_art[0]);
|
||||||
|
int art_width = splash_art[0].length();
|
||||||
|
|
||||||
|
int start_row = (height - art_height) / 2;
|
||||||
|
int start_col = (width - art_width) / 2;
|
||||||
|
|
||||||
|
if (start_row < 0) start_row = 0;
|
||||||
|
if (start_col < 0) start_col = 0;
|
||||||
|
|
||||||
|
// Draw shadow
|
||||||
|
attron(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
for (int i = 0; i < art_height; ++i) {
|
||||||
|
mvprintw(start_row + i + 1, start_col + 1, "%s", splash_art[i].c_str());
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
|
||||||
|
// Draw main art
|
||||||
|
attron(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
for (int i = 0; i < art_height; ++i) {
|
||||||
|
mvprintw(start_row + i, start_col, "%s", splash_art[i].c_str());
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
std::string loading_msg = "Loading...";
|
||||||
|
mvprintw(start_row + art_height + 2, (width - loading_msg.length()) / 2, "%s", loading_msg.c_str());
|
||||||
|
attroff(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(2)); // Display for 2 seconds
|
||||||
|
|
||||||
|
endwin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,6 @@ void run_tui(const std::vector<IcsEvent> &events);
|
||||||
// 运行 ncurses TUI for the portal
|
// 运行 ncurses TUI for the portal
|
||||||
int run_portal_tui();
|
int run_portal_tui();
|
||||||
|
|
||||||
|
// 显示启动画面
|
||||||
|
void display_splash_screen();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue