mirror of
https://github.com/eddyem/eddys_snippets.git
synced 2025-12-06 02:35:12 +03:00
add some ncurses snippets
This commit is contained in:
parent
1af9716058
commit
dbe431a121
13
Ncurses/Makefile
Normal file
13
Ncurses/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
CC=gcc
|
||||||
|
CFLAGS= -Wall -Werror -Wextra -O3 `pkg-config --libs --cflags ncurses`
|
||||||
|
|
||||||
|
all: menu mouse_menu acs rolling readf ncurses_and_readline
|
||||||
|
|
||||||
|
ncurses_and_readline: ncurses_and_readline.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) $(CFLAGS) -lreadline -o $@ $<
|
||||||
|
|
||||||
|
%: %.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
45
Ncurses/acs.c
Normal file
45
Ncurses/acs.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
initscr();
|
||||||
|
|
||||||
|
printw("Upper right corner "); addch(ACS_URCORNER); printw("\n");
|
||||||
|
printw("Upper left corner "); addch(ACS_ULCORNER); printw("\n");
|
||||||
|
printw("Lower left corner "); addch(ACS_LLCORNER); printw("\n");
|
||||||
|
printw("Lower right corner "); addch(ACS_LRCORNER); printw("\n");
|
||||||
|
printw("Tee pointing right "); addch(ACS_LTEE); printw("\n");
|
||||||
|
printw("Tee pointing left "); addch(ACS_RTEE); printw("\n");
|
||||||
|
printw("Tee pointing up "); addch(ACS_BTEE); printw("\n");
|
||||||
|
printw("Tee pointing down "); addch(ACS_TTEE); printw("\n");
|
||||||
|
printw("Horizontal line "); addch(ACS_HLINE); printw("\n");
|
||||||
|
printw("Vertical line "); addch(ACS_VLINE); printw("\n");
|
||||||
|
printw("Large Plus or cross over "); addch(ACS_PLUS); printw("\n");
|
||||||
|
printw("Scan Line 1 "); addch(ACS_S1); printw("\n");
|
||||||
|
printw("Scan Line 3 "); addch(ACS_S3); printw("\n");
|
||||||
|
printw("Scan Line 7 "); addch(ACS_S7); printw("\n");
|
||||||
|
printw("Scan Line 9 "); addch(ACS_S9); printw("\n");
|
||||||
|
printw("Diamond "); addch(ACS_DIAMOND); printw("\n");
|
||||||
|
printw("Checker board (stipple) "); addch(ACS_CKBOARD); printw("\n");
|
||||||
|
printw("Degree Symbol "); addch(ACS_DEGREE); printw("\n");
|
||||||
|
printw("Plus/Minus Symbol "); addch(ACS_PLMINUS); printw("\n");
|
||||||
|
printw("Bullet "); addch(ACS_BULLET); printw("\n");
|
||||||
|
printw("Arrow Pointing Left "); addch(ACS_LARROW); printw("\n");
|
||||||
|
printw("Arrow Pointing Right "); addch(ACS_RARROW); printw("\n");
|
||||||
|
printw("Arrow Pointing Down "); addch(ACS_DARROW); printw("\n");
|
||||||
|
printw("Arrow Pointing Up "); addch(ACS_UARROW); printw("\n");
|
||||||
|
printw("Board of squares "); addch(ACS_BOARD); printw("\n");
|
||||||
|
printw("Lantern Symbol "); addch(ACS_LANTERN); printw("\n");
|
||||||
|
printw("Solid Square Block "); addch(ACS_BLOCK); printw("\n");
|
||||||
|
printw("Less/Equal sign "); addch(ACS_LEQUAL); printw("\n");
|
||||||
|
printw("Greater/Equal sign "); addch(ACS_GEQUAL); printw("\n");
|
||||||
|
printw("Pi "); addch(ACS_PI); printw("\n");
|
||||||
|
printw("Not equal "); addch(ACS_NEQUAL); printw("\n");
|
||||||
|
printw("UK pound sign "); addch(ACS_STERLING); printw("\n");
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
getch();
|
||||||
|
endwin();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
94
Ncurses/menu.c
Normal file
94
Ncurses/menu.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
#define WIDTH 30
|
||||||
|
#define HEIGHT 10
|
||||||
|
|
||||||
|
int startx = 0;
|
||||||
|
int starty = 0;
|
||||||
|
|
||||||
|
char *choices[] = {
|
||||||
|
"Choice 1",
|
||||||
|
"Choice 2",
|
||||||
|
"Choice 3",
|
||||||
|
"Choice 4",
|
||||||
|
"Exit",
|
||||||
|
};
|
||||||
|
int n_choices = sizeof(choices) / sizeof(char *);
|
||||||
|
void print_menu(WINDOW *menu_win, int highlight);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{ WINDOW *menu_win;
|
||||||
|
int highlight = 1;
|
||||||
|
int choice = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
initscr();
|
||||||
|
clear();
|
||||||
|
noecho();
|
||||||
|
cbreak(); /* Line buffering disabled. pass on everything */
|
||||||
|
startx = (80 - WIDTH) / 2;
|
||||||
|
starty = (24 - HEIGHT) / 2;
|
||||||
|
|
||||||
|
menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
||||||
|
keypad(menu_win, TRUE);
|
||||||
|
mvprintw(0, 0, "Use arrow keys to go up and down, Press enter to select a choice");
|
||||||
|
refresh();
|
||||||
|
print_menu(menu_win, highlight);
|
||||||
|
while(1)
|
||||||
|
{ c = wgetch(menu_win);
|
||||||
|
switch(c)
|
||||||
|
{ case KEY_UP:
|
||||||
|
if(highlight == 1)
|
||||||
|
highlight = n_choices;
|
||||||
|
else
|
||||||
|
--highlight;
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
if(highlight == n_choices)
|
||||||
|
highlight = 1;
|
||||||
|
else
|
||||||
|
++highlight;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
choice = highlight;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mvprintw(24, 0, "Charcter pressed is = %3d", c);
|
||||||
|
if(c > 32 && c < 256) printw(" (%c)", c);
|
||||||
|
clrtoeol();
|
||||||
|
refresh();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
print_menu(menu_win, highlight);
|
||||||
|
if(choice != 0) /* User did a choice come out of the infinite loop */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mvprintw(23, 0, "You chose choice %d with choice string %s\n", choice, choices[choice - 1]);
|
||||||
|
clrtoeol();
|
||||||
|
refresh();
|
||||||
|
sleep(1);
|
||||||
|
endwin();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void print_menu(WINDOW *menu_win, int highlight)
|
||||||
|
{
|
||||||
|
int x, y, i;
|
||||||
|
|
||||||
|
x = 2;
|
||||||
|
y = 2;
|
||||||
|
box(menu_win, 0, 0);
|
||||||
|
for(i = 0; i < n_choices; ++i)
|
||||||
|
{ if(highlight == i + 1) /* High light the present choice */
|
||||||
|
{ wattron(menu_win, A_REVERSE);
|
||||||
|
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||||
|
wattroff(menu_win, A_REVERSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
wrefresh(menu_win);
|
||||||
|
}
|
||||||
132
Ncurses/mouse_menu.c
Normal file
132
Ncurses/mouse_menu.c
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define WIDTH 30
|
||||||
|
#define HEIGHT 10
|
||||||
|
|
||||||
|
int startx = 0;
|
||||||
|
int starty = 0;
|
||||||
|
|
||||||
|
char *choices[] = { "Choice 1",
|
||||||
|
"Choice 2",
|
||||||
|
"Choice 3",
|
||||||
|
"Choice 4",
|
||||||
|
"Exit",
|
||||||
|
};
|
||||||
|
|
||||||
|
int n_choices = sizeof(choices) / sizeof(char *);
|
||||||
|
|
||||||
|
void print_menu(WINDOW *menu_win, int choice);
|
||||||
|
void report_choice(int mouse_x, int mouse_y, int *p_choice);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{ int c, choice = 0, highlight = 1;
|
||||||
|
WINDOW *menu_win;
|
||||||
|
MEVENT event;
|
||||||
|
|
||||||
|
/* Initialize curses */
|
||||||
|
initscr();
|
||||||
|
clear();
|
||||||
|
noecho();
|
||||||
|
cbreak(); //Line buffering disabled. pass on everything
|
||||||
|
|
||||||
|
/* Try to put the window in the middle of screen */
|
||||||
|
startx = (80 - WIDTH) / 2;
|
||||||
|
starty = (24 - HEIGHT) / 2;
|
||||||
|
|
||||||
|
attron(A_REVERSE);
|
||||||
|
mvprintw(23, 1, "startx=%d, starty=%d", startx, starty);
|
||||||
|
refresh();
|
||||||
|
attroff(A_REVERSE);
|
||||||
|
|
||||||
|
/* Print the menu for the first time */
|
||||||
|
menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
||||||
|
keypad(menu_win, TRUE);
|
||||||
|
print_menu(menu_win, 1);
|
||||||
|
/* Get all the mouse events */
|
||||||
|
mousemask(ALL_MOUSE_EVENTS, NULL);
|
||||||
|
while(1)
|
||||||
|
{ c = wgetch(menu_win);
|
||||||
|
mvprintw(4, 1, "Character pressed is = %3d", c);
|
||||||
|
refresh();
|
||||||
|
switch(c)
|
||||||
|
{ case KEY_MOUSE:
|
||||||
|
if(getmouse(&event) == OK){ /* When the user clicks left mouse button */
|
||||||
|
mvprintw(5, 1, "x=%d, y=%d, bstate=0x%08x", event.x, event.y, event.bstate);
|
||||||
|
clrtoeol();
|
||||||
|
refresh();
|
||||||
|
if(event.bstate & (BUTTON1_PRESSED|BUTTON1_CLICKED))
|
||||||
|
{
|
||||||
|
report_choice(event.x + 1, event.y + 1, &choice);
|
||||||
|
if(choice == -1) //Exit chosen
|
||||||
|
goto end;
|
||||||
|
mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]);
|
||||||
|
clrtoeol();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
refresh();
|
||||||
|
if(highlight == 1)
|
||||||
|
highlight = n_choices;
|
||||||
|
else
|
||||||
|
--highlight;
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
if(highlight == n_choices)
|
||||||
|
highlight = 1;
|
||||||
|
else
|
||||||
|
++highlight;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
choice = highlight;
|
||||||
|
mvprintw(2, 1, "Choice: %d", choice);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
print_menu(menu_win, highlight);
|
||||||
|
refresh();
|
||||||
|
if(choice == n_choices) break;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
endwin();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void print_menu(WINDOW *menu_win, int choice)
|
||||||
|
{
|
||||||
|
int x, y, i;
|
||||||
|
|
||||||
|
x = 2;
|
||||||
|
y = 2;
|
||||||
|
box(menu_win, 0, 0);
|
||||||
|
for(i = 0; i < n_choices; ++i)
|
||||||
|
{ if(choice == i + 1)
|
||||||
|
{ wattron(menu_win, A_REVERSE);
|
||||||
|
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||||
|
wattroff(menu_win, A_REVERSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||||
|
++y;
|
||||||
|
}
|
||||||
|
wrefresh(menu_win);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Report the choice according to mouse position */
|
||||||
|
void report_choice(int mouse_x, int mouse_y, int *p_choice)
|
||||||
|
{ int i,j, choice;
|
||||||
|
|
||||||
|
i = startx + 2;
|
||||||
|
j = starty + 3;
|
||||||
|
|
||||||
|
for(choice = 0; choice < n_choices; ++choice)
|
||||||
|
if(mouse_y == j + choice && mouse_x >= i && mouse_x <= i + (int)strlen(choices[choice]))
|
||||||
|
{ if(choice == n_choices - 1)
|
||||||
|
*p_choice = -1;
|
||||||
|
else
|
||||||
|
*p_choice = choice + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Ncurses/ncurses.cflags
Normal file
1
Ncurses/ncurses.cflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c17
|
||||||
2
Ncurses/ncurses.config
Normal file
2
Ncurses/ncurses.config
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// Add predefined macros for your project here. For example:
|
||||||
|
// #define THE_ANSWER 42
|
||||||
1
Ncurses/ncurses.creator
Normal file
1
Ncurses/ncurses.creator
Normal file
@ -0,0 +1 @@
|
|||||||
|
[General]
|
||||||
1
Ncurses/ncurses.cxxflags
Normal file
1
Ncurses/ncurses.cxxflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c++17
|
||||||
7
Ncurses/ncurses.files
Normal file
7
Ncurses/ncurses.files
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
acs.c
|
||||||
|
menu.c
|
||||||
|
mouse_menu.c
|
||||||
|
ncurses_and_readline.c
|
||||||
|
rolling.c
|
||||||
|
scroll.c
|
||||||
|
scrollfile.c
|
||||||
1
Ncurses/ncurses.includes
Normal file
1
Ncurses/ncurses.includes
Normal file
@ -0,0 +1 @@
|
|||||||
|
.
|
||||||
336
Ncurses/ncurses_and_readline.c
Normal file
336
Ncurses/ncurses_and_readline.c
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ncurses project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// based on https://stackoverflow.com/a/28709979/1965803 ->
|
||||||
|
// https://github.com/ulfalizer/readline-and-ncurses
|
||||||
|
// Copyright (c) 2015-2019, Ulf Magnusson
|
||||||
|
// SPDX-License-Identifier: ISC
|
||||||
|
|
||||||
|
#include <curses.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Keeps track of the terminal mode so we can reset the terminal if needed on errors
|
||||||
|
static bool visual_mode = false;
|
||||||
|
// insert commands when true; roll upper screen when false
|
||||||
|
static bool insert_mode = true;
|
||||||
|
static bool should_exit = false;
|
||||||
|
|
||||||
|
static void fail_exit(const char *msg){
|
||||||
|
// Make sure endwin() is only called in visual mode. As a note, calling it
|
||||||
|
// twice does not seem to be supported and messed with the cursor position.
|
||||||
|
if(visual_mode) endwin();
|
||||||
|
fprintf(stderr, "%s\n", msg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WINDOW *msg_win; // Message window
|
||||||
|
static WINDOW *sep_win; // Separator line above the command (readline) window
|
||||||
|
static WINDOW *cmd_win; // Command (readline) window
|
||||||
|
|
||||||
|
// string list
|
||||||
|
typedef struct _Line{
|
||||||
|
int Nline;
|
||||||
|
char *contents;
|
||||||
|
struct _Line *prev, *next;
|
||||||
|
} Line;
|
||||||
|
// head of list, current item and first line on screen
|
||||||
|
Line *head = NULL, *curr = NULL, *firstline = NULL;
|
||||||
|
int nr_lines = 0; // total anount of data portions @ input
|
||||||
|
|
||||||
|
static unsigned char input; // Input character for readline
|
||||||
|
|
||||||
|
// Used to signal "no more input" after feeding a character to readline
|
||||||
|
static bool input_avail = false;
|
||||||
|
|
||||||
|
// Not bothering with 'input_avail' and just returning 0 here seems to do the
|
||||||
|
// right thing too, but this might be safer across readline versions
|
||||||
|
static int readline_input_avail(){
|
||||||
|
return input_avail;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int readline_getc(__attribute__((__unused__)) FILE *dummy){
|
||||||
|
input_avail = false;
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void forward_to_readline(char c){
|
||||||
|
input = c;
|
||||||
|
input_avail = true;
|
||||||
|
rl_callback_read_char();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msg_win_redisplay(bool for_resize){
|
||||||
|
werase(msg_win);
|
||||||
|
Line *l = firstline;
|
||||||
|
int nlines = 0; // total amount of lines @ output
|
||||||
|
for(; l && (nlines < LINES - 2); l = l->next){
|
||||||
|
size_t contlen = strlen(l->contents) + 128;
|
||||||
|
char *buf = malloc(contlen);
|
||||||
|
// don't add trailing '\n' (or last line will be empty with cursor)
|
||||||
|
contlen = snprintf(buf, contlen, "%s", l->contents);
|
||||||
|
int nlnext = (contlen - 1) / COLS + 1;
|
||||||
|
wmove(msg_win, nlines, 0);
|
||||||
|
if(nlines + nlnext < LINES-2){ // can put out the full line
|
||||||
|
waddstr(msg_win, buf);
|
||||||
|
//wprintw(msg_win, "%d (%d): %s -> %d", l->Nline, firstline->Nline, l->contents, nlnext);
|
||||||
|
nlines += nlnext;
|
||||||
|
}else{ // put only first part
|
||||||
|
int rest = LINES-2 - nlines;
|
||||||
|
waddnstr(msg_win, buf, rest *COLS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
curs_set(0);
|
||||||
|
if(for_resize) wnoutrefresh(msg_win);
|
||||||
|
else wrefresh(msg_win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void got_command(char *line){
|
||||||
|
if(!line) // Ctrl-D pressed on empty line
|
||||||
|
should_exit = true;
|
||||||
|
else{
|
||||||
|
if(!*line) return; // zero length
|
||||||
|
add_history(line);
|
||||||
|
Line *lp = malloc(sizeof(Line));
|
||||||
|
lp->contents = line;
|
||||||
|
lp->prev = curr;
|
||||||
|
lp->next = NULL;
|
||||||
|
lp->Nline = nr_lines++;
|
||||||
|
if(!curr || !head){
|
||||||
|
head = curr = firstline = lp;
|
||||||
|
}else
|
||||||
|
curr->next = lp;
|
||||||
|
curr = lp;
|
||||||
|
// roll back to show last input
|
||||||
|
if(curr->prev){
|
||||||
|
firstline = curr;
|
||||||
|
int totalln = (strlen(firstline->contents) - 1)/COLS + 1;
|
||||||
|
while(firstline->prev){
|
||||||
|
totalln += (strlen(firstline->prev->contents) - 1)/COLS + 1;
|
||||||
|
if(totalln > LINES-2) break;
|
||||||
|
firstline = firstline->prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg_win_redisplay(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_win_redisplay(bool for_resize){
|
||||||
|
int cursor_col = 2 + rl_point; // "> " width is 2
|
||||||
|
werase(cmd_win);
|
||||||
|
int x = 0, maxw = COLS-2;
|
||||||
|
if(cursor_col > maxw){
|
||||||
|
x = cursor_col - maxw;
|
||||||
|
cursor_col = maxw;
|
||||||
|
}
|
||||||
|
char abuf[4096];
|
||||||
|
snprintf(abuf, 4096, "> %s", rl_line_buffer);
|
||||||
|
waddstr(cmd_win, abuf+x);
|
||||||
|
wmove(cmd_win, 0, cursor_col);
|
||||||
|
curs_set(2);
|
||||||
|
if(for_resize) wnoutrefresh(cmd_win);
|
||||||
|
else wrefresh(cmd_win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readline_redisplay(void){
|
||||||
|
cmd_win_redisplay(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_mode(bool for_resize){
|
||||||
|
wclear(sep_win);
|
||||||
|
if(insert_mode) waddstr(sep_win, "INSERT (TAB to switch, ctrl+D to quit)");
|
||||||
|
else waddstr(sep_win, "SCROLL (TAB to switch, q to quit)");
|
||||||
|
if(for_resize) wnoutrefresh(sep_win);
|
||||||
|
else wrefresh(sep_win);
|
||||||
|
cmd_win_redisplay(for_resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resize(void){
|
||||||
|
if(LINES > 2){
|
||||||
|
wresize(msg_win, LINES - 2, COLS);
|
||||||
|
wresize(sep_win, 1, COLS);
|
||||||
|
wresize(cmd_win, 1, COLS);
|
||||||
|
mvwin(sep_win, LINES - 2, 0);
|
||||||
|
mvwin(cmd_win, LINES - 1, 0);
|
||||||
|
}
|
||||||
|
msg_win_redisplay(true);
|
||||||
|
show_mode(true);
|
||||||
|
doupdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_ncurses(void){
|
||||||
|
if (!initscr())
|
||||||
|
fail_exit("Failed to initialize ncurses");
|
||||||
|
visual_mode = true;
|
||||||
|
if(has_colors()){
|
||||||
|
start_color();
|
||||||
|
use_default_colors();
|
||||||
|
}
|
||||||
|
cbreak();
|
||||||
|
noecho();
|
||||||
|
nonl();
|
||||||
|
intrflush(NULL, FALSE);
|
||||||
|
// Do not enable keypad() since we want to pass unadulterated input to readline
|
||||||
|
keypad(cmd_win, 0);
|
||||||
|
// Explicitly specify a "very visible" cursor to make sure it's at least
|
||||||
|
// consistent when we turn the cursor on and off (maybe it would make sense
|
||||||
|
// to query it and use the value we get back too). "normal" vs. "very
|
||||||
|
// visible" makes no difference in gnome-terminal or xterm. Let this fail
|
||||||
|
// for terminals that do not support cursor visibility adjustments.
|
||||||
|
curs_set(2);
|
||||||
|
if(LINES > 2){
|
||||||
|
msg_win = newwin(LINES - 2, COLS, 0, 0);
|
||||||
|
sep_win = newwin(1, COLS, LINES - 2, 0);
|
||||||
|
cmd_win = newwin(1, COLS, LINES - 1, 0);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Degenerate case. Give the windows the minimum workable size to
|
||||||
|
// prevent errors from e.g. wmove().
|
||||||
|
msg_win = newwin(1, COLS, 0, 0);
|
||||||
|
sep_win = newwin(1, COLS, 0, 0);
|
||||||
|
cmd_win = newwin(1, COLS, 0, 0);
|
||||||
|
}
|
||||||
|
if(!msg_win || !sep_win || !cmd_win)
|
||||||
|
fail_exit("Failed to allocate windows");
|
||||||
|
// Allow strings longer than the command window and show only the last part if the string doesn't fit
|
||||||
|
// scrollok(cmd_win, TRUE);
|
||||||
|
if(has_colors()){
|
||||||
|
// Use white-on-blue cells for the separator window...
|
||||||
|
init_pair(1, COLOR_WHITE, COLOR_BLUE);
|
||||||
|
wbkgd(sep_win, COLOR_PAIR(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// ...or the "best highlighting mode of the terminal" if it doesn't
|
||||||
|
// support colors
|
||||||
|
wbkgd(sep_win, A_STANDOUT);
|
||||||
|
show_mode(false);
|
||||||
|
mousemask(BUTTON4_PRESSED|BUTTON5_PRESSED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deinit_ncurses(void){
|
||||||
|
delwin(msg_win);
|
||||||
|
delwin(sep_win);
|
||||||
|
delwin(cmd_win);
|
||||||
|
endwin();
|
||||||
|
visual_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_readline(void){
|
||||||
|
// Let ncurses do all terminal and signal handling
|
||||||
|
rl_catch_signals = 0;
|
||||||
|
rl_catch_sigwinch = 0;
|
||||||
|
rl_deprep_term_function = NULL;
|
||||||
|
rl_prep_term_function = NULL;
|
||||||
|
// Prevent readline from setting the LINES and COLUMNS environment
|
||||||
|
// variables, which override dynamic size adjustments in ncurses. When
|
||||||
|
// using the alternate readline interface (as we do here), LINES and
|
||||||
|
// COLUMNS are not updated if the terminal is resized between two calls to
|
||||||
|
// rl_callback_read_char() (which is almost always the case).
|
||||||
|
rl_change_environment = 0;
|
||||||
|
// Handle input by manually feeding characters to readline
|
||||||
|
rl_getc_function = readline_getc;
|
||||||
|
rl_input_available_hook = readline_input_avail;
|
||||||
|
rl_redisplay_function = readline_redisplay;
|
||||||
|
rl_callback_handler_install("> ", got_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deinit_readline(void){
|
||||||
|
rl_callback_handler_remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rolldown(){
|
||||||
|
if(firstline && firstline->prev){
|
||||||
|
firstline = firstline->prev;
|
||||||
|
msg_win_redisplay(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rollup(){
|
||||||
|
if(firstline && firstline->next){
|
||||||
|
firstline = firstline->next;
|
||||||
|
msg_win_redisplay(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
init_ncurses();
|
||||||
|
init_readline();
|
||||||
|
MEVENT event;
|
||||||
|
do{
|
||||||
|
int c = wgetch(cmd_win);
|
||||||
|
bool processed = true;
|
||||||
|
switch(c){
|
||||||
|
case KEY_MOUSE:
|
||||||
|
if(getmouse(&event) == OK){
|
||||||
|
if(event.bstate & (BUTTON4_PRESSED)) rolldown(); // wheel up
|
||||||
|
else if(event.bstate & (BUTTON5_PRESSED)) rollup(); // wheel down
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\t': // tab switch between scroll and edit mode
|
||||||
|
keypad(cmd_win, insert_mode); // enable/disable reaction @ special characters
|
||||||
|
insert_mode = !insert_mode;
|
||||||
|
show_mode(false);
|
||||||
|
break;
|
||||||
|
case KEY_RESIZE:
|
||||||
|
resize();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
processed = false;
|
||||||
|
}
|
||||||
|
if(processed) continue;
|
||||||
|
if(insert_mode){
|
||||||
|
forward_to_readline(c);
|
||||||
|
}else{
|
||||||
|
switch(c){
|
||||||
|
case KEY_UP: // roll down for one item
|
||||||
|
rolldown();
|
||||||
|
break;
|
||||||
|
case KEY_DOWN: // roll up for one item
|
||||||
|
rollup();
|
||||||
|
break;
|
||||||
|
case KEY_PPAGE: // PageUp: roll down for 10 items
|
||||||
|
for(int i = 0; i < 10; ++i){
|
||||||
|
if(firstline && firstline->prev) firstline = firstline->prev;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
msg_win_redisplay(false);
|
||||||
|
break;
|
||||||
|
case KEY_NPAGE: // PageUp: roll up for 10 items
|
||||||
|
for(int i = 0; i < 10; ++i){
|
||||||
|
if(firstline && firstline->next) firstline = firstline->next;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
msg_win_redisplay(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(c == 'q' || c == 'Q') should_exit = true; // quit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}while(!should_exit);
|
||||||
|
deinit_ncurses();
|
||||||
|
deinit_readline();
|
||||||
|
puts("Shut down cleanly");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
28
Ncurses/rolling.c
Normal file
28
Ncurses/rolling.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <curses.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int maxx, maxy;
|
||||||
|
|
||||||
|
|
||||||
|
void initscreen(){
|
||||||
|
initscr();
|
||||||
|
getmaxyx(stdscr, maxy, maxx); // getyx - get current coords
|
||||||
|
cbreak();
|
||||||
|
keypad(stdscr, TRUE); // We get F1, F2 etc..
|
||||||
|
noecho();
|
||||||
|
nodelay(stdscr, TRUE); // getch() returns ERR if no keys pressed
|
||||||
|
start_color();
|
||||||
|
init_pair(1, COLOR_RED, COLOR_BLACK);
|
||||||
|
init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
||||||
|
init_pair(3, COLOR_YELLOW, COLOR_BLACK);
|
||||||
|
init_pair(4, COLOR_BLUE, COLOR_BLACK);
|
||||||
|
init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
|
||||||
|
init_pair(6, COLOR_CYAN, COLOR_BLACK);
|
||||||
|
init_pair(7, COLOR_WHITE, COLOR_BLACK);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
initscreen();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
110
Ncurses/scroll.c
Normal file
110
Ncurses/scroll.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define MAXLEN 127
|
||||||
|
|
||||||
|
typedef struct Line {
|
||||||
|
char *contents;
|
||||||
|
struct Line *prev, *next;
|
||||||
|
} Line;
|
||||||
|
|
||||||
|
char inputstr[MAXLEN+1] = {0};
|
||||||
|
int currinp = 0;
|
||||||
|
|
||||||
|
Line *head = NULL, *curr = NULL, *firstline = NULL;
|
||||||
|
|
||||||
|
int refreshmain = 1, refreshstr = 1;
|
||||||
|
|
||||||
|
int nr_lines;
|
||||||
|
int curr_line;
|
||||||
|
WINDOW *mainwin, *onestring;
|
||||||
|
|
||||||
|
int term_rows, term_cols;
|
||||||
|
|
||||||
|
void draw(Line *l);
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Line *lp;
|
||||||
|
// printf("\033c"); - cls
|
||||||
|
initscr();
|
||||||
|
noecho();
|
||||||
|
getmaxyx(stdscr, term_rows, term_cols);
|
||||||
|
term_rows -= 2;
|
||||||
|
mainwin = newwin(term_rows, term_cols, 0, 0);
|
||||||
|
onestring = newwin(1, term_cols, term_rows+1, 0);
|
||||||
|
keypad(onestring, TRUE); // for KEY_UP, KEY_DOWN
|
||||||
|
|
||||||
|
curr_line = 0;
|
||||||
|
|
||||||
|
draw(curr);
|
||||||
|
|
||||||
|
int ch;
|
||||||
|
while ((ch = wgetch(onestring)) != EOF)
|
||||||
|
{
|
||||||
|
if (ch == KEY_UP && firstline->prev != NULL)
|
||||||
|
{
|
||||||
|
curr_line--;
|
||||||
|
firstline = firstline->prev;
|
||||||
|
refreshmain = 1;
|
||||||
|
}
|
||||||
|
else if (ch == KEY_DOWN && firstline->next != NULL && curr_line + term_rows < nr_lines)
|
||||||
|
{
|
||||||
|
curr_line++;
|
||||||
|
firstline = firstline->next;
|
||||||
|
refreshmain = 1;
|
||||||
|
}
|
||||||
|
else if(ch == 10 && currinp){
|
||||||
|
lp = malloc(sizeof(Line));
|
||||||
|
lp->contents = strdup(inputstr);
|
||||||
|
lp->prev = curr;
|
||||||
|
lp->next = NULL;
|
||||||
|
if(!curr || !head){
|
||||||
|
head = curr = firstline = lp;
|
||||||
|
}else
|
||||||
|
curr->next = lp;
|
||||||
|
curr = lp;
|
||||||
|
++nr_lines;
|
||||||
|
while(nr_lines - curr_line > term_rows){
|
||||||
|
curr_line++;
|
||||||
|
firstline = firstline->next;
|
||||||
|
}
|
||||||
|
currinp = 0;
|
||||||
|
inputstr[0] = 0;
|
||||||
|
refreshstr = 1;
|
||||||
|
refreshmain = 1;
|
||||||
|
}else if(ch >= ' ' && ch < 256 && ch != 127){
|
||||||
|
if(currinp > MAXLEN){
|
||||||
|
wclear(onestring);
|
||||||
|
waddstr(onestring, "Limit reached!");
|
||||||
|
wrefresh(onestring);
|
||||||
|
}else{
|
||||||
|
inputstr[currinp++] = ch;
|
||||||
|
inputstr[currinp] = 0;
|
||||||
|
}
|
||||||
|
refreshstr = 1;
|
||||||
|
}
|
||||||
|
draw(firstline);
|
||||||
|
}
|
||||||
|
|
||||||
|
endwin();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Line *l){
|
||||||
|
if(refreshmain){
|
||||||
|
refreshmain = 0;
|
||||||
|
wclear(mainwin);
|
||||||
|
for(int i = 0; i < term_rows && l != NULL; i++, l = l->next)
|
||||||
|
wprintw(mainwin, "%s\n", l->contents);
|
||||||
|
wrefresh(mainwin);
|
||||||
|
}
|
||||||
|
if(refreshstr){
|
||||||
|
refreshstr = 0;
|
||||||
|
wclear(onestring);
|
||||||
|
wprintw(onestring, " > %s", inputstr);
|
||||||
|
wrefresh(onestring);
|
||||||
|
}
|
||||||
|
}
|
||||||
128
Ncurses/scrollfile.c
Normal file
128
Ncurses/scrollfile.c
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define MAXLEN 128
|
||||||
|
|
||||||
|
typedef struct Line {
|
||||||
|
char contents[MAXLEN];
|
||||||
|
struct Line *prev, *next;
|
||||||
|
} Line;
|
||||||
|
|
||||||
|
#define MAXSTRL 120
|
||||||
|
char inputstr[MAXSTRL+1] = {0};
|
||||||
|
int currinp = 0;
|
||||||
|
|
||||||
|
Line *head, *curr;
|
||||||
|
|
||||||
|
int refreshmain = 1, refreshstr = 1;
|
||||||
|
|
||||||
|
int nr_lines;
|
||||||
|
int curr_line;
|
||||||
|
WINDOW *mainwin, *onestring;
|
||||||
|
|
||||||
|
int term_rows, term_cols;
|
||||||
|
|
||||||
|
void load(const char *filename);
|
||||||
|
void draw(Line *l);
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
fputs("less: No file to open\n", stderr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
initscr();
|
||||||
|
noecho();
|
||||||
|
getmaxyx(stdscr, term_rows, term_cols);
|
||||||
|
term_rows -= 2;
|
||||||
|
mainwin = newwin(term_rows, term_cols, 0, 0);
|
||||||
|
onestring = newwin(1, term_cols, term_rows+1, 0);
|
||||||
|
keypad(onestring, TRUE); // for KEY_UP, KEY_DOWN
|
||||||
|
|
||||||
|
waddstr(mainwin, "Reading text...\n");
|
||||||
|
wrefresh(mainwin);
|
||||||
|
sleep(1);
|
||||||
|
load(argv[1]);
|
||||||
|
|
||||||
|
curr = head;
|
||||||
|
curr_line = 0;
|
||||||
|
|
||||||
|
draw(curr);
|
||||||
|
|
||||||
|
int ch;
|
||||||
|
while ((ch = wgetch(onestring)) != EOF)
|
||||||
|
{
|
||||||
|
if (ch == KEY_UP && curr->prev != NULL)
|
||||||
|
{
|
||||||
|
curr_line--;
|
||||||
|
curr = curr->prev;
|
||||||
|
refreshmain = 1;
|
||||||
|
}
|
||||||
|
else if (ch == KEY_DOWN && curr->next != NULL
|
||||||
|
&& curr_line + term_rows < nr_lines)
|
||||||
|
{
|
||||||
|
curr_line++;
|
||||||
|
curr = curr->next;
|
||||||
|
refreshmain = 1;
|
||||||
|
}
|
||||||
|
else if(ch == 10){
|
||||||
|
currinp = 0;
|
||||||
|
inputstr[0] = 0;
|
||||||
|
refreshstr = 1;
|
||||||
|
}else if(ch >= ' ' && ch < 256 && ch != 127){
|
||||||
|
if(currinp > MAXSTRL){
|
||||||
|
wclear(onestring);
|
||||||
|
waddstr(onestring, "Limit reached!");
|
||||||
|
wrefresh(onestring);
|
||||||
|
}else{
|
||||||
|
inputstr[currinp++] = ch;
|
||||||
|
inputstr[currinp] = 0;
|
||||||
|
}
|
||||||
|
refreshstr = 1;
|
||||||
|
}
|
||||||
|
draw(curr);
|
||||||
|
}
|
||||||
|
|
||||||
|
endwin();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load(const char *filename)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen(filename, "r");
|
||||||
|
Line *lp;
|
||||||
|
|
||||||
|
head = malloc(sizeof(Line));
|
||||||
|
head->prev = head->next = NULL;
|
||||||
|
curr = head;
|
||||||
|
|
||||||
|
while (fgets(curr->contents, MAXLEN, fp))
|
||||||
|
{
|
||||||
|
lp = malloc(sizeof(Line));
|
||||||
|
lp->prev = curr;
|
||||||
|
curr->next = lp;
|
||||||
|
curr = lp;
|
||||||
|
nr_lines++;
|
||||||
|
}
|
||||||
|
curr->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Line *l)
|
||||||
|
{
|
||||||
|
if(refreshmain){
|
||||||
|
refreshmain = 0;
|
||||||
|
wclear(mainwin);
|
||||||
|
for(int i = 0; i < term_rows && l != NULL; i++, l = l->next)
|
||||||
|
waddstr(mainwin, l->contents);
|
||||||
|
wrefresh(mainwin);
|
||||||
|
}
|
||||||
|
if(refreshstr){
|
||||||
|
refreshstr = 0;
|
||||||
|
wclear(onestring);
|
||||||
|
wprintw(onestring, " > %s", inputstr);
|
||||||
|
wrefresh(onestring);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user