311 lines
6.3 KiB
C++
311 lines
6.3 KiB
C++
// (C) 2018 by folkert@vanheusden.com, released under AGPL 3.0
|
|
#include <algorithm>
|
|
#include <assert.h>
|
|
#include <ncursesw/curses.h>
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include "terminal.h"
|
|
#include "error.h"
|
|
#include "utils.h"
|
|
|
|
int max_x = 80, max_y = 25;
|
|
|
|
void determine_terminal_size()
|
|
{
|
|
struct winsize size;
|
|
|
|
if (ioctl(1, TIOCGWINSZ, &size) == 0)
|
|
{
|
|
max_y = size.ws_row;
|
|
max_x = size.ws_col;
|
|
}
|
|
else
|
|
{
|
|
char *dummy = getenv("COLUMNS");
|
|
if (dummy)
|
|
max_x = atoi(dummy);
|
|
|
|
dummy = getenv("LINES");
|
|
if (dummy)
|
|
max_x = atoi(dummy);
|
|
}
|
|
}
|
|
|
|
void apply_mouse_setting(void)
|
|
{
|
|
mousemask(0, nullptr);
|
|
}
|
|
|
|
void init_ncurses(bool init_mouse)
|
|
{
|
|
initscr();
|
|
start_color();
|
|
use_default_colors();
|
|
keypad(stdscr, TRUE);
|
|
cbreak();
|
|
intrflush(stdscr, FALSE);
|
|
noecho();
|
|
nonl();
|
|
refresh();
|
|
nodelay(stdscr, TRUE);
|
|
meta(stdscr, TRUE); /* enable 8-bit input */
|
|
raw(); /* to be able to catch ctrl+c */
|
|
leaveok(stdscr, FALSE);
|
|
|
|
if (init_mouse)
|
|
apply_mouse_setting();
|
|
|
|
max_y = LINES;
|
|
max_x = COLS;
|
|
}
|
|
|
|
void wrong_key(void)
|
|
{
|
|
flash();
|
|
beep();
|
|
flushinp();
|
|
}
|
|
|
|
void color_on(NEWWIN *win, int pair)
|
|
{
|
|
wattron(win -> win, COLOR_PAIR(pair));
|
|
}
|
|
|
|
void color_off(NEWWIN *win, int pair)
|
|
{
|
|
wattroff(win -> win, COLOR_PAIR(pair));
|
|
}
|
|
|
|
void delete_window(NEWWIN *mywin)
|
|
{
|
|
mydelwin(mywin);
|
|
|
|
free(mywin);
|
|
}
|
|
|
|
void mydelwin(NEWWIN *win)
|
|
{
|
|
if (win)
|
|
{
|
|
if (win -> pwin && ERR == del_panel(win -> pwin))
|
|
error_exit(false, "del_panel() failed");
|
|
|
|
if (win -> win && ERR == delwin(win -> win))
|
|
error_exit(false, "delwin() failed");
|
|
}
|
|
}
|
|
|
|
void mydoupdate()
|
|
{
|
|
update_panels();
|
|
|
|
doupdate();
|
|
}
|
|
|
|
WINDOW * mynewwin(int nlines, int ncols, int y, int x)
|
|
{
|
|
assert(x >= 0 && y >= 0);
|
|
assert(x < max_x && y < max_y);
|
|
assert(x + ncols <= max_x && y + nlines <= max_y);
|
|
|
|
WINDOW *dummy = newwin(nlines, ncols, y, x);
|
|
if (!dummy)
|
|
error_exit(false, "failed to create window (subwin) with dimensions %d-%d at offset %d,%d (terminal size: %d,%d)", ncols, nlines, x, y, max_x, max_y);
|
|
|
|
keypad(dummy, TRUE);
|
|
leaveok(dummy, TRUE);
|
|
|
|
return dummy;
|
|
}
|
|
|
|
NEWWIN * create_window(int n_lines, int n_colls)
|
|
{
|
|
return create_window_xy((max_y/2) - (n_lines/2), (max_x/2) - (n_colls/2), n_lines, n_colls);
|
|
}
|
|
|
|
NEWWIN * create_window_xy(int y, int x, int n_lines, int n_colls)
|
|
{
|
|
assert(x >= 0 && y >= 0);
|
|
assert(x < max_x && y < max_y);
|
|
assert(x + n_colls <= max_x && y + n_lines <= max_y);
|
|
NEWWIN *newwin = (NEWWIN *)malloc(sizeof(NEWWIN));
|
|
|
|
/* create new window */
|
|
newwin -> win = mynewwin(n_lines, n_colls, y, x);
|
|
newwin -> pwin = new_panel(newwin -> win);
|
|
werase(newwin -> win);
|
|
|
|
newwin -> ncols = n_colls;
|
|
newwin -> nlines = n_lines;
|
|
|
|
newwin -> x = x;
|
|
newwin -> y = y;
|
|
|
|
return newwin;
|
|
}
|
|
|
|
void limit_print(NEWWIN *win, int width, int y, int x, char *format, ...)
|
|
{
|
|
va_list ap;
|
|
int len = 0;
|
|
char *buf = nullptr;
|
|
|
|
va_start(ap, format);
|
|
len = vasprintf(&buf, format, ap);
|
|
va_end(ap);
|
|
|
|
if (len > width)
|
|
buf[width] = 0x00;
|
|
|
|
mvwprintw(win -> win, y, x, "%s", buf);
|
|
|
|
free(buf);
|
|
}
|
|
|
|
void escape_print_xy(NEWWIN *win, int y, int x, char *str)
|
|
{
|
|
int loop = 0, cursor_x = 0, len = strlen(str);
|
|
bool inv = false, underline = false;
|
|
|
|
for(loop=0; loop<len; loop++)
|
|
{
|
|
if (str[loop] == '^')
|
|
{
|
|
if (!inv)
|
|
mywattron(win -> win, A_REVERSE);
|
|
else
|
|
mywattroff(win -> win, A_REVERSE);
|
|
|
|
inv = 1 - inv;
|
|
}
|
|
else if (str[loop] == '_')
|
|
{
|
|
if (!underline)
|
|
mywattron(win -> win, A_UNDERLINE);
|
|
else
|
|
mywattroff(win -> win, A_UNDERLINE);
|
|
|
|
underline = 1 - underline;
|
|
}
|
|
else if (str[loop] == '\n')
|
|
{
|
|
cursor_x = 0;
|
|
y++;
|
|
}
|
|
else
|
|
{
|
|
mvwprintw(win -> win, y, x + cursor_x++, "%c", str[loop]);
|
|
}
|
|
}
|
|
|
|
if (inv)
|
|
mywattroff(win -> win, A_REVERSE);
|
|
|
|
if (underline)
|
|
mywattroff(win -> win, A_UNDERLINE);
|
|
}
|
|
|
|
void escape_print(NEWWIN *win, const char *str, const char rev, const char un)
|
|
{
|
|
int loop, len = strlen(str);
|
|
bool inv = false, underline = false;
|
|
|
|
for(loop=0; loop<len; loop++)
|
|
{
|
|
if (str[loop] == rev)
|
|
{
|
|
if (!inv)
|
|
mywattron(win -> win, A_REVERSE);
|
|
else
|
|
mywattroff(win -> win, A_REVERSE);
|
|
|
|
inv = 1 - inv;
|
|
}
|
|
else if (str[loop] == un)
|
|
{
|
|
if (!underline)
|
|
mywattron(win -> win, A_UNDERLINE);
|
|
else
|
|
mywattroff(win -> win, A_UNDERLINE);
|
|
|
|
underline = 1 - underline;
|
|
}
|
|
else
|
|
{
|
|
waddch(win -> win, str[loop]);
|
|
}
|
|
}
|
|
|
|
if (inv)
|
|
mywattroff(win -> win, A_REVERSE);
|
|
|
|
if (underline)
|
|
mywattroff(win -> win, A_UNDERLINE);
|
|
}
|
|
|
|
void create_win_border(int x, int y, int width, int height, const char *title, NEWWIN **bwin, NEWWIN **win, bool f1, bool with_blank_border)
|
|
{
|
|
assert(x >= 0 && y >= 0);
|
|
assert(x < max_x && y < max_y);
|
|
assert(x + width <= max_x && y + height <= max_y);
|
|
const char f1_for_help [] = " F1 for help ";
|
|
|
|
bool wbb = with_blank_border;
|
|
|
|
*bwin = create_window_xy(y + 0, x + 0, height + 2 + wbb * 2, width + 2 + wbb * 2);
|
|
*win = create_window_xy(y + 1 + wbb, x + 1 + wbb, height + 0, width + 0);
|
|
|
|
mywattron((*bwin) -> win, A_REVERSE);
|
|
box((*bwin) -> win, 0, 0);
|
|
mywattroff((*bwin) -> win, A_REVERSE);
|
|
|
|
mywattron((*bwin) -> win, A_STANDOUT);
|
|
|
|
mvwprintw((*bwin) -> win, 0, 1, "[ %s ]", title);
|
|
|
|
if (f1)
|
|
mvwprintw((*bwin) -> win, (*bwin) -> nlines - 1, 2, "[ %s ]", f1_for_help);
|
|
|
|
mywattroff((*bwin) -> win, A_STANDOUT);
|
|
}
|
|
|
|
void create_wb_popup(int width, int height, const char *title, NEWWIN **bwin, NEWWIN **win)
|
|
{
|
|
create_win_border(max_x / 2 - width / 2, max_y / 2 - height / 2, width, height, title, bwin, win, false, true);
|
|
}
|
|
|
|
void mywattron(WINDOW *w, int a)
|
|
{
|
|
if (a != A_BLINK && a != A_BOLD && a != A_NORMAL && a != A_REVERSE && a != A_STANDOUT && a != A_UNDERLINE)
|
|
error_exit(false, "funny attributes: %d", a);
|
|
|
|
wattron(w, a);
|
|
}
|
|
|
|
void mywattroff(WINDOW *w, int a)
|
|
{
|
|
if (a != A_BLINK && a != A_BOLD && a != A_NORMAL && a != A_REVERSE && a != A_STANDOUT && a != A_UNDERLINE)
|
|
error_exit(false, "funny attributes: %d", a);
|
|
|
|
wattroff(w, a);
|
|
}
|
|
|
|
void reset_attributes(NEWWIN *win)
|
|
{
|
|
wattrset(win -> win, A_NORMAL);
|
|
}
|
|
|
|
bool is_in_window(NEWWIN *win, int x, int y)
|
|
{
|
|
return wenclose(win -> win, y, x);
|
|
}
|
|
|
|
bool right_mouse_button_clicked(void)
|
|
{
|
|
MEVENT event;
|
|
|
|
return getmouse(&event) == OK && (event.bstate & BUTTON3_CLICKED);
|
|
}
|