mirror of
https://github.com/m1ngsama/TUT.git
synced 2025-12-24 10:51:46 +00:00
Merge pull request #7 from m1ngsama/feature/tui-interface-enhancement
feat: Enhance TUI interface with modern design and ASCII compatibility
This commit is contained in:
commit
1e9b523130
1 changed files with 358 additions and 88 deletions
446
src/tui_view.cpp
446
src/tui_view.cpp
|
|
@ -11,25 +11,109 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Define color pairs
|
// Define color pairs - Modern btop-inspired color scheme
|
||||||
enum ColorPairs {
|
enum ColorPairs {
|
||||||
NORMAL_TEXT = 1,
|
NORMAL_TEXT = 1, // Default white text
|
||||||
SHADOW_TEXT,
|
SHADOW_TEXT, // Dim shadow text
|
||||||
BANNER_TEXT,
|
BANNER_TEXT, // Bright cyan for banners
|
||||||
SELECTED_ITEM
|
SELECTED_ITEM, // Bright yellow for selected items
|
||||||
|
BORDER_LINE, // Gray borders and boxes
|
||||||
|
SUCCESS_TEXT, // Green for success states
|
||||||
|
WARNING_TEXT, // Orange/yellow for warnings
|
||||||
|
ERROR_TEXT, // Red for errors
|
||||||
|
INFO_TEXT, // Blue for information
|
||||||
|
ACCENT_TEXT, // Magenta for accents
|
||||||
|
DIM_TEXT, // Dimmed secondary text
|
||||||
|
PROGRESS_BAR, // Green progress bars
|
||||||
|
CALENDAR_HEADER, // Calendar header styling
|
||||||
|
EVENT_PAST, // Grayed out past events
|
||||||
|
EVENT_TODAY, // Highlighted today's events
|
||||||
|
EVENT_UPCOMING // Default upcoming events
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_colors() {
|
void init_colors() {
|
||||||
if (has_colors()) {
|
if (has_colors()) {
|
||||||
start_color();
|
start_color();
|
||||||
use_default_colors(); // Use terminal's default background
|
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)
|
// Modern color scheme inspired by btop
|
||||||
init_pair(BANNER_TEXT, COLOR_CYAN, -1); // Cyan foreground, default background
|
init_pair(NORMAL_TEXT, COLOR_WHITE, -1); // White text
|
||||||
init_pair(SELECTED_ITEM, COLOR_YELLOW, -1); // Yellow foreground, default background
|
init_pair(SHADOW_TEXT, COLOR_BLACK, -1); // Black shadow text
|
||||||
|
init_pair(BANNER_TEXT, COLOR_CYAN, -1); // Bright cyan for banners
|
||||||
|
init_pair(SELECTED_ITEM, COLOR_YELLOW, -1); // Bright yellow selection
|
||||||
|
init_pair(BORDER_LINE, COLOR_BLUE, -1); // Blue borders/boxes
|
||||||
|
init_pair(SUCCESS_TEXT, COLOR_GREEN, -1); // Green for success
|
||||||
|
init_pair(WARNING_TEXT, COLOR_YELLOW, -1); // Orange/yellow warnings
|
||||||
|
init_pair(ERROR_TEXT, COLOR_RED, -1); // Red for errors
|
||||||
|
init_pair(INFO_TEXT, COLOR_BLUE, -1); // Blue for info
|
||||||
|
init_pair(ACCENT_TEXT, COLOR_MAGENTA, -1); // Magenta accents
|
||||||
|
init_pair(DIM_TEXT, COLOR_BLACK, -1); // Dimmed text
|
||||||
|
init_pair(PROGRESS_BAR, COLOR_GREEN, -1); // Green progress
|
||||||
|
init_pair(CALENDAR_HEADER, COLOR_CYAN, -1); // Calendar headers
|
||||||
|
init_pair(EVENT_PAST, COLOR_BLACK, -1); // Grayed past events
|
||||||
|
init_pair(EVENT_TODAY, COLOR_YELLOW, -1); // Today's events highlighted
|
||||||
|
init_pair(EVENT_UPCOMING, COLOR_WHITE, -1); // Default upcoming events
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to draw a box
|
||||||
|
void draw_box(int start_y, int start_x, int width, int height, bool shadow = false) {
|
||||||
|
if (shadow) {
|
||||||
|
// Draw shadow first
|
||||||
|
attron(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
for (int i = 0; i < height; i++) {
|
||||||
|
mvprintw(start_y + i + 1, start_x + 1, "%s", std::string(width, ' ').c_str());
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(SHADOW_TEXT));
|
||||||
|
}
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(BORDER_LINE));
|
||||||
|
// Draw corners
|
||||||
|
mvprintw(start_y, start_x, "┌");
|
||||||
|
mvprintw(start_y, start_x + width - 1, "┐");
|
||||||
|
mvprintw(start_y + height - 1, start_x, "└");
|
||||||
|
mvprintw(start_y + height - 1, start_x + width - 1, "┘");
|
||||||
|
|
||||||
|
// Draw horizontal lines
|
||||||
|
for (int i = 1; i < width - 1; i++) {
|
||||||
|
mvprintw(start_y, start_x + i, "─");
|
||||||
|
mvprintw(start_y + height - 1, start_x + i, "─");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw vertical lines
|
||||||
|
for (int i = 1; i < height - 1; i++) {
|
||||||
|
mvprintw(start_y + i, start_x, "│");
|
||||||
|
mvprintw(start_y + i, start_x + width - 1, "│");
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(BORDER_LINE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to draw a progress bar
|
||||||
|
void draw_progress_bar(int y, int x, int width, float percentage) {
|
||||||
|
int filled_width = static_cast<int>(width * percentage);
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(BORDER_LINE));
|
||||||
|
mvprintw(y, x, "[");
|
||||||
|
mvprintw(y, x + width - 1, "]");
|
||||||
|
attroff(COLOR_PAIR(BORDER_LINE));
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(PROGRESS_BAR));
|
||||||
|
for (int i = 1; i < filled_width && i < width - 1; i++) {
|
||||||
|
mvprintw(y, x + i, "█");
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(PROGRESS_BAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to center text within a box
|
||||||
|
void draw_centered_text(int y, int box_start_x, int box_width, const std::string& text, int color_pair = NORMAL_TEXT) {
|
||||||
|
int text_x = box_start_x + (box_width - text.length()) / 2;
|
||||||
|
if (text_x < box_start_x) text_x = box_start_x;
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(color_pair));
|
||||||
|
mvprintw(y, text_x, "%s", text.c_str());
|
||||||
|
attroff(COLOR_PAIR(color_pair));
|
||||||
|
}
|
||||||
|
|
||||||
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{};
|
||||||
|
|
@ -43,6 +127,23 @@ std::string format_date(const std::chrono::system_clock::time_point &tp) {
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to check if event is today, past, or upcoming
|
||||||
|
int get_event_status(const std::chrono::system_clock::time_point &event_time) {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
if (event_time < now) {
|
||||||
|
return EVENT_PAST;
|
||||||
|
} else {
|
||||||
|
// Simple check if it's today (within 24 hours)
|
||||||
|
auto hours_until_event = std::chrono::duration_cast<std::chrono::hours>(event_time - now);
|
||||||
|
if (hours_until_event.count() <= 24) {
|
||||||
|
return EVENT_TODAY;
|
||||||
|
} else {
|
||||||
|
return EVENT_UPCOMING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void run_tui(const std::vector<IcsEvent> &events) {
|
void run_tui(const std::vector<IcsEvent> &events) {
|
||||||
|
|
@ -79,14 +180,11 @@ void run_tui(const std::vector<IcsEvent> &events) {
|
||||||
while (true) {
|
while (true) {
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
// ASCII art banner for "CALENDAR"
|
// Modern ASCII art banner for "CALENDAR" - smaller and cleaner
|
||||||
std::string calendar_banner[] = {
|
std::string calendar_banner[] = {
|
||||||
" ██████╗ █████╗ ██╗ ███████╗███╗ ██╗██████╗ █████╗ ██████╗ ",
|
" ╔═══════════════════════════════════╗ ",
|
||||||
"██╔════╝██╔══██╗██║ ██╔════╝████╗ ██║██╔══██╗██╔══██╗██╔══██╗",
|
" ║ [CAL] NBTCA CALENDAR [CAL] ║ ",
|
||||||
"██║ ███████║██║ █████╗ ██╔██╗ ██║██║ ██║███████║██████╔╝",
|
" ╚═══════════════════════════════════╝ "
|
||||||
"██║ ██╔══██║██║ ██╔══╝ ██║╚██╗██║██║ ██║██╔══██║██╔══██╗",
|
|
||||||
"╚██████╗██║ ██║███████╗███████╗██║ ╚████║██████╔╝██║ ██║██║ ██║",
|
|
||||||
" ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝╚╝ ╚═╝"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int banner_height = sizeof(calendar_banner) / sizeof(calendar_banner[0]);
|
int banner_height = sizeof(calendar_banner) / sizeof(calendar_banner[0]);
|
||||||
|
|
@ -109,51 +207,131 @@ void run_tui(const std::vector<IcsEvent> &events) {
|
||||||
}
|
}
|
||||||
attroff(COLOR_PAIR(BANNER_TEXT));
|
attroff(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
|
||||||
attron(COLOR_PAIR(NORMAL_TEXT));
|
// Draw status bar with current date and event count
|
||||||
std::string instruction_msg = "(q 退出, ↑↓ 滚动)";
|
attron(COLOR_PAIR(BORDER_LINE));
|
||||||
mvprintw(banner_height + 1, (width - instruction_msg.length()) / 2, "%s", instruction_msg.c_str());
|
mvprintw(banner_height + 1, 0, "┌");
|
||||||
attroff(COLOR_PAIR(NORMAL_TEXT));
|
mvprintw(banner_height + 1, width - 1, "┐");
|
||||||
|
for (int i = 1; i < width - 1; i++) {
|
||||||
|
mvprintw(banner_height + 1, i, "─");
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(BORDER_LINE));
|
||||||
|
|
||||||
|
// Status information
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto tt = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm tm{};
|
||||||
|
#if defined(_WIN32)
|
||||||
|
localtime_s(&tm, &tt);
|
||||||
|
#else
|
||||||
|
localtime_r(&tt, &tm);
|
||||||
|
#endif
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::put_time(&tm, "%Y-%m-%d %A");
|
||||||
|
std::string current_date = "Today: " + oss.str() + " | Events: " + std::to_string(events.size());
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(INFO_TEXT));
|
||||||
|
mvprintw(banner_height + 1, 2, "%s", current_date.c_str());
|
||||||
|
attroff(COLOR_PAIR(INFO_TEXT));
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(DIM_TEXT));
|
||||||
|
std::string instruction_msg = "[q:Exit ↑↓:Scroll]";
|
||||||
|
mvprintw(banner_height + 1, width - instruction_msg.length() - 2, "%s", instruction_msg.c_str());
|
||||||
|
attroff(COLOR_PAIR(DIM_TEXT));
|
||||||
|
|
||||||
int start_event_row = banner_height + 3; // Start events below the banner and instruction
|
int start_event_row = banner_height + 3; // Start events below the banner and instruction
|
||||||
int visibleLines = height - start_event_row - 1; // Adjust visible lines
|
int visibleLines = height - start_event_row - 2; // Leave space for bottom border
|
||||||
|
|
||||||
|
// Draw main event container box
|
||||||
|
draw_box(start_event_row - 1, 0, width, visibleLines + 2, true);
|
||||||
|
|
||||||
|
// Header for events list
|
||||||
|
attron(COLOR_PAIR(CALENDAR_HEADER));
|
||||||
|
mvprintw(start_event_row, 2, "╓ Upcoming Events");
|
||||||
|
attroff(COLOR_PAIR(CALENDAR_HEADER));
|
||||||
|
|
||||||
|
int events_start_row = start_event_row + 1;
|
||||||
|
int events_visible_lines = visibleLines - 2;
|
||||||
|
|
||||||
if (selected < top) {
|
if (selected < top) {
|
||||||
top = selected;
|
top = selected;
|
||||||
} else if (selected >= top + visibleLines) {
|
} else if (selected >= top + events_visible_lines) {
|
||||||
top = selected - visibleLines + 1;
|
top = selected - events_visible_lines + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < visibleLines; ++i) {
|
for (int i = 0; i < events_visible_lines; ++i) {
|
||||||
int idx = top + i;
|
int idx = top + i;
|
||||||
if (idx >= static_cast<int>(events.size())) break;
|
if (idx >= static_cast<int>(events.size())) break;
|
||||||
|
|
||||||
const auto &ev = events[idx];
|
const auto &ev = events[idx];
|
||||||
std::string line = format_date(ev.start) + " " + ev.summary;
|
int event_status = get_event_status(ev.start);
|
||||||
|
|
||||||
|
// Event icon based on status
|
||||||
|
std::string icon = "○";
|
||||||
|
if (event_status == EVENT_TODAY) {
|
||||||
|
icon = "*";
|
||||||
|
} else if (event_status == EVENT_PAST) {
|
||||||
|
icon = "v";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format date more compactly
|
||||||
|
auto tt = std::chrono::system_clock::to_time_t(ev.start);
|
||||||
|
std::tm tm{};
|
||||||
|
#if defined(_WIN32)
|
||||||
|
localtime_s(&tm, &tt);
|
||||||
|
#else
|
||||||
|
localtime_r(&tt, &tm);
|
||||||
|
#endif
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::put_time(&tm, "%m/%d %H:%M");
|
||||||
|
std::string date_str = oss.str();
|
||||||
|
|
||||||
|
// Build the event line
|
||||||
|
std::string line = icon + " " + date_str + " " + ev.summary;
|
||||||
if (!ev.location.empty()) {
|
if (!ev.location.empty()) {
|
||||||
line += " @" + ev.location;
|
line += " @" + ev.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int)line.size() > width - 1) {
|
// Truncate if too long
|
||||||
line.resize(width - 1);
|
if ((int)line.length() > width - 4) {
|
||||||
|
line.resize(width - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine colors based on event status and selection
|
||||||
|
int text_color = (event_status == EVENT_PAST) ? DIM_TEXT :
|
||||||
|
(event_status == EVENT_TODAY) ? EVENT_TODAY :
|
||||||
|
EVENT_UPCOMING;
|
||||||
|
|
||||||
if (idx == selected) {
|
if (idx == selected) {
|
||||||
attron(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
attron(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
mvprintw(start_event_row + i, 0, "%s", line.c_str());
|
mvprintw(events_start_row + i, 2, "%s", std::string(width - 4, ' ').c_str());
|
||||||
|
mvprintw(events_start_row + i, 3, "%s", line.c_str());
|
||||||
attroff(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
attroff(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
} else {
|
} else {
|
||||||
attron(COLOR_PAIR(NORMAL_TEXT));
|
attron(COLOR_PAIR(text_color));
|
||||||
mvprintw(start_event_row + i, 0, "%s", line.c_str());
|
mvprintw(events_start_row + i, 3, "%s", line.c_str());
|
||||||
attroff(COLOR_PAIR(NORMAL_TEXT));
|
attroff(COLOR_PAIR(text_color));
|
||||||
}
|
}
|
||||||
// Add a separator after each event
|
|
||||||
if (i < visibleLines - 1 && idx + 1 < static_cast<int>(events.size())) {
|
// Add a subtle separator
|
||||||
attron(COLOR_PAIR(SHADOW_TEXT));
|
if (i < events_visible_lines - 1 && idx + 1 < static_cast<int>(events.size())) {
|
||||||
mvprintw(start_event_row + i + 1, 0, "%s", std::string(width, '-').c_str()); // Dynamic separator
|
attron(COLOR_PAIR(BORDER_LINE));
|
||||||
attroff(COLOR_PAIR(SHADOW_TEXT));
|
mvprintw(events_start_row + i + 1, 2, "├");
|
||||||
|
for (int j = 3; j < width - 2; j++) {
|
||||||
|
mvprintw(events_start_row + i + 1, j, "─");
|
||||||
|
}
|
||||||
|
mvprintw(events_start_row + i + 1, width - 2, "┤");
|
||||||
|
attroff(COLOR_PAIR(BORDER_LINE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add scroll indicator if there are more events
|
||||||
|
if (events.size() > events_visible_lines) {
|
||||||
|
float scroll_percentage = static_cast<float>(top + events_visible_lines) / events.size();
|
||||||
|
int scroll_y = start_event_row + 1;
|
||||||
|
int scroll_x = width - 3;
|
||||||
|
draw_progress_bar(scroll_y, scroll_x, 1, scroll_percentage);
|
||||||
|
}
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
int ch = getch();
|
int ch = getch();
|
||||||
|
|
@ -189,14 +367,11 @@ int run_portal_tui() {
|
||||||
while (choice == -1) {
|
while (choice == -1) {
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
// ASCII art banner for "NBTCA Tools"
|
// Modern ASCII art banner for "NBTCA Tools" - smaller and cleaner
|
||||||
std::string banner_art[] = {
|
std::string banner_art[] = {
|
||||||
"███╗ ██╗██████╗ ████████╗ ██████╗ █████╗ ████████╗ ██████╗ ██████╗ ██╗ ███████╗",
|
" ╔══════════════════════════════════════╗ ",
|
||||||
"████╗ ██║██╔══██╗╚══██╔══╝██╔════╝██╔══██╗ ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██╔════╝",
|
" ║ [TOOL] NBTCA UTILITY TOOLS [TOOL] ║ ",
|
||||||
"██╔██╗ ██║██████╔╝ ██║ ██║ ███████║ ██║ ██║ ██║██║ ██║██║ ███████╗",
|
" ╚══════════════════════════════════════╝ "
|
||||||
"██║╚██╗██║██╔══██╗ ██║ ██║ ██╔══██║ ██║ ██║ ██║██║ ██║██║ ╚════██║",
|
|
||||||
"██║ ╚████║██████╔╝ ██║ ╚██████╗██║ ██║ ██║ ╚██████╔╝╚██████╔╝███████╗███████║",
|
|
||||||
"╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int banner_height = sizeof(banner_art) / sizeof(banner_art[0]);
|
int banner_height = sizeof(banner_art) / sizeof(banner_art[0]);
|
||||||
|
|
@ -219,22 +394,79 @@ int run_portal_tui() {
|
||||||
}
|
}
|
||||||
attroff(COLOR_PAIR(BANNER_TEXT));
|
attroff(COLOR_PAIR(BANNER_TEXT));
|
||||||
|
|
||||||
attron(COLOR_PAIR(NORMAL_TEXT));
|
// Draw info bar
|
||||||
// Feature Portal message below the banner
|
attron(COLOR_PAIR(BORDER_LINE));
|
||||||
std::string portal_msg = "Feature Portal (q or Enter to select)";
|
mvprintw(banner_height + 1, 0, "┌");
|
||||||
mvprintw(banner_height + 1, (width - portal_msg.length()) / 2, "%s", portal_msg.c_str());
|
mvprintw(banner_height + 1, width - 1, "┐");
|
||||||
attroff(COLOR_PAIR(NORMAL_TEXT));
|
for (int i = 1; i < width - 1; i++) {
|
||||||
|
mvprintw(banner_height + 1, i, "─");
|
||||||
|
}
|
||||||
|
attroff(COLOR_PAIR(BORDER_LINE));
|
||||||
|
|
||||||
|
// Status information
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto tt = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm tm{};
|
||||||
|
#if defined(_WIN32)
|
||||||
|
localtime_s(&tm, &tt);
|
||||||
|
#else
|
||||||
|
localtime_r(&tt, &tm);
|
||||||
|
#endif
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
|
||||||
|
std::string current_time = "Current: " + oss.str();
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(INFO_TEXT));
|
||||||
|
mvprintw(banner_height + 1, 2, "%s", current_time.c_str());
|
||||||
|
attroff(COLOR_PAIR(INFO_TEXT));
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(DIM_TEXT));
|
||||||
|
std::string help_msg = "[↑↓:Navigate Enter:Select q:Exit]";
|
||||||
|
mvprintw(banner_height + 1, width - help_msg.length() - 2, "%s", help_msg.c_str());
|
||||||
|
attroff(COLOR_PAIR(DIM_TEXT));
|
||||||
|
|
||||||
|
// Draw menu box
|
||||||
|
int menu_box_y = banner_height + 3;
|
||||||
|
int menu_box_height = menu_items.size() + 4;
|
||||||
|
int menu_box_width = 30;
|
||||||
|
int menu_box_x = (width - menu_box_width) / 2;
|
||||||
|
if (menu_box_x < 2) menu_box_x = 2;
|
||||||
|
|
||||||
|
draw_box(menu_box_y, menu_box_x, menu_box_width, menu_box_height, true);
|
||||||
|
|
||||||
|
// Menu box title
|
||||||
|
attron(COLOR_PAIR(CALENDAR_HEADER));
|
||||||
|
draw_centered_text(menu_box_y + 1, menu_box_x, menu_box_width, "Select Module");
|
||||||
|
attroff(COLOR_PAIR(CALENDAR_HEADER));
|
||||||
|
|
||||||
|
// Draw menu items with icons
|
||||||
for (size_t i = 0; i < menu_items.size(); ++i) {
|
for (size_t i = 0; i < menu_items.size(); ++i) {
|
||||||
|
std::string display_item = menu_items[i];
|
||||||
|
|
||||||
|
// Add icons to menu items
|
||||||
|
if (display_item == "Calendar") {
|
||||||
|
display_item = "[CAL] " + display_item;
|
||||||
|
} else if (display_item == "Exit") {
|
||||||
|
display_item = "[X] " + display_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
int item_y = menu_box_y + 2 + i;
|
||||||
|
|
||||||
if ((int)i == selected) {
|
if ((int)i == selected) {
|
||||||
|
// Draw selection highlight box
|
||||||
|
attron(COLOR_PAIR(BORDER_LINE));
|
||||||
|
mvprintw(item_y, menu_box_x + 1, "│");
|
||||||
|
mvprintw(item_y, menu_box_x + menu_box_width - 2, "│");
|
||||||
|
attroff(COLOR_PAIR(BORDER_LINE));
|
||||||
|
|
||||||
attron(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
attron(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
|
draw_centered_text(item_y, menu_box_x, menu_box_width, display_item, SELECTED_ITEM);
|
||||||
|
attroff(A_REVERSE | COLOR_PAIR(SELECTED_ITEM));
|
||||||
} else {
|
} else {
|
||||||
attron(COLOR_PAIR(NORMAL_TEXT));
|
attron(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
draw_centered_text(item_y, menu_box_x, menu_box_width, display_item);
|
||||||
|
attroff(COLOR_PAIR(NORMAL_TEXT));
|
||||||
}
|
}
|
||||||
// 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();
|
||||||
|
|
@ -279,48 +511,86 @@ void display_splash_screen() {
|
||||||
int height, width;
|
int height, width;
|
||||||
getmaxyx(stdscr, height, width);
|
getmaxyx(stdscr, height, width);
|
||||||
|
|
||||||
clear();
|
// Animated splash screen with progress bar
|
||||||
|
for (int frame = 0; frame < 20; ++frame) {
|
||||||
|
clear();
|
||||||
|
|
||||||
// Simple ASCII art for "NBTCA Tools"
|
// Modern ASCII art for "NBTCA Tools" - cleaner design
|
||||||
std::string splash_art[] = {
|
std::string splash_art[] = {
|
||||||
"███╗ ██╗██████╗ ████████╗ ██████╗ █████╗ ████████╗ ██████╗ ██████╗ ██╗ ███████╗",
|
" ╔══════════════════════════════════════╗ ",
|
||||||
"████╗ ██║██╔══██╗╚══██╔══╝██╔════╝██╔══██╗ ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██╔════╝",
|
" ║ [TOOL] NBTCA UTILITY TOOLS [TOOL] ║ ",
|
||||||
"██╔██╗ ██║██████╔╝ ██║ ██║ ███████║ ██║ ██║ ██║██║ ██║██║ ███████╗",
|
" ╚══════════════════════════════════════╝ "
|
||||||
"██║╚██╗██║██╔══██╗ ██║ ██║ ██╔══██║ ██║ ██║ ██║██║ ██║██║ ╚════██║",
|
};
|
||||||
"██║ ╚████║██████╔╝ ██║ ╚██████╗██║ ██║ ██║ ╚██████╔╝╚██████╔╝███████╗███████║",
|
|
||||||
"╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝"
|
|
||||||
};
|
|
||||||
|
|
||||||
int art_height = sizeof(splash_art) / sizeof(splash_art[0]);
|
int art_height = sizeof(splash_art) / sizeof(splash_art[0]);
|
||||||
int art_width = splash_art[0].length();
|
int art_width = splash_art[0].length();
|
||||||
|
|
||||||
int start_row = (height - art_height) / 2;
|
int start_row = (height - art_height) / 2 - 3;
|
||||||
int start_col = (width - art_width) / 2;
|
int start_col = (width - art_width) / 2;
|
||||||
|
|
||||||
if (start_row < 0) start_row = 0;
|
if (start_row < 0) start_row = 0;
|
||||||
if (start_col < 0) start_col = 0;
|
if (start_col < 0) start_col = 0;
|
||||||
|
|
||||||
// Draw shadow
|
// Draw shadow
|
||||||
attron(COLOR_PAIR(SHADOW_TEXT));
|
attron(COLOR_PAIR(SHADOW_TEXT));
|
||||||
for (int i = 0; i < art_height; ++i) {
|
for (int i = 0; i < art_height; ++i) {
|
||||||
mvprintw(start_row + i + 1, start_col + 1, "%s", splash_art[i].c_str());
|
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));
|
||||||
|
|
||||||
|
// Version info
|
||||||
|
attron(COLOR_PAIR(INFO_TEXT));
|
||||||
|
draw_centered_text(start_row + art_height + 1, start_col, art_width, "Version 0.0.1");
|
||||||
|
attroff(COLOR_PAIR(INFO_TEXT));
|
||||||
|
|
||||||
|
// Loading text with rotating animation
|
||||||
|
const char* spinner[] = {"|", "/", "-", "\\"};
|
||||||
|
std::string loading_msg = std::string(spinner[frame % 4]) + " Initializing system components...";
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
draw_centered_text(start_row + art_height + 3, start_col, art_width, loading_msg);
|
||||||
|
attroff(COLOR_PAIR(NORMAL_TEXT));
|
||||||
|
|
||||||
|
// Progress bar
|
||||||
|
int progress_bar_y = start_row + art_height + 5;
|
||||||
|
int progress_bar_width = 40;
|
||||||
|
int progress_bar_x = (width - progress_bar_width) / 2;
|
||||||
|
|
||||||
|
float progress = static_cast<float>(frame) / 19.0f;
|
||||||
|
draw_progress_bar(progress_bar_y, progress_bar_x, progress_bar_width, progress);
|
||||||
|
|
||||||
|
// Progress percentage
|
||||||
|
attron(COLOR_PAIR(SUCCESS_TEXT));
|
||||||
|
std::string progress_text = std::to_string(static_cast<int>(progress * 100)) + "% Complete";
|
||||||
|
draw_centered_text(progress_bar_y + 1, progress_bar_x, progress_bar_width, progress_text);
|
||||||
|
attroff(COLOR_PAIR(SUCCESS_TEXT));
|
||||||
|
|
||||||
|
// Status messages
|
||||||
|
std::vector<std::string> status_msgs = {
|
||||||
|
"Loading calendar module...",
|
||||||
|
"Initializing network stack...",
|
||||||
|
"Fetching latest events...",
|
||||||
|
"Preparing user interface...",
|
||||||
|
"System ready!"
|
||||||
|
};
|
||||||
|
|
||||||
|
int msg_index = (frame * status_msgs.size()) / 20;
|
||||||
|
if (msg_index >= status_msgs.size()) msg_index = status_msgs.size() - 1;
|
||||||
|
|
||||||
|
attron(COLOR_PAIR(DIM_TEXT));
|
||||||
|
draw_centered_text(progress_bar_y + 2, progress_bar_x, progress_bar_width, status_msgs[msg_index]);
|
||||||
|
attroff(COLOR_PAIR(DIM_TEXT));
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100ms per frame
|
||||||
}
|
}
|
||||||
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();
|
endwin();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue