Skip to content

Instantly share code, notes, and snippets.

@etzl
Last active Oct 25, 2020
Embed
What would you like to do?
ncurses with panels a customizable window inside terminal - but not very functional :)
#include <curses.h>
#include <panel.h>
#include <string.h>
#include <stdlib.h>
#define NLINES 10
#define NCOLS 40
#define COUNT 3
#define TEELINE 2
typedef struct __PANEL_DATA {
int x,y, height, width;
int label_color;
char label[80];
PANEL* next;
} PANEL_DATA;
void init(WINDOW **wins, PANEL **all_panels);
void win_show(WINDOW *win, char *label, int label_color);
void print_in_middle(WINDOW* win, int maxx, int teeline, char *string,
chtype color);
void operate_on_panel(PANEL* top);
void move_mode(PANEL* top);
void resize_mode(PANEL* top);
int main()
{
WINDOW *my_wins[COUNT];
PANEL *my_panels[COUNT];
PANEL *top;
int ch;
/* Initialize curses */
initscr();
start_color();
cbreak();
noecho();
keypad(stdscr, TRUE);
/* Initialize all the colors */
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_BLUE, COLOR_BLACK);
init_pair(4, COLOR_CYAN, COLOR_BLACK);
chtype notice_color = COLOR_PAIR(4);
init(my_wins, my_panels);
/* Update the stacking order. 3rd panel will be on top */
update_panels();
/* Show it on the screen */
attron(notice_color);
mvprintw(LINES - 2, 0, "Use <tab> to browse, <m> to move, <r> to resize, <Enter> to write (F1 to Exit)");
attroff(notice_color);
refresh();
top = my_panels[2];
PANEL_DATA* current_data = (PANEL_DATA*)panel_userptr(top);
while((ch = getch()) != KEY_F(1))
{ switch(ch)
{
case 'm':
attron(notice_color);
mvprintw(LINES-3, 0, "You can move panels with arrow keys (use <Enter> to exit!)");
attroff(notice_color);
refresh();
move_mode(top);
break;
case 'r':
attron(notice_color);
mvprintw(LINES-3, 0, "Use arrow keys to resize window and press <Enter> when you're done!");
attroff(notice_color);
refresh();
resize_mode(top);
break;
case '\t':
top_panel(current_data->next);
top = current_data->next;
current_data = (PANEL_DATA*)panel_userptr(top);
update_panels();
doupdate();
break;
case '\n': // allow user to insert text in the current panel
attron(notice_color);
mvprintw(LINES - 3, 0, "Entered writing mode use <Esc> to exit");
attroff(notice_color);
refresh();
operate_on_panel(top);
break;
}
}
endwin();
return 0;
}
void move_mode(PANEL* top)
{
PANEL_DATA* data = (PANEL_DATA*)panel_userptr(top);
int c;
while ((c = getch()) != 10) {
switch (c) {
case KEY_UP:
--data->y;
break;
case KEY_DOWN:
++data->y;
break;
case KEY_LEFT:
--data->x;
break;
case KEY_RIGHT:
++data->x;
break;
}
move_panel(top, data->y, data->x);
update_panels();
doupdate();
}
move(LINES-3, 0);
clrtoeol();
refresh();
update_panels();
doupdate();
}
void resize_mode(PANEL* top)
{
PANEL_DATA* data = (PANEL_DATA*)panel_userptr(top);
int ch;
while ((ch = getch()) != 10) {
switch (ch) {
case KEY_UP:
--(data->y);
++(data->height);
break;
case KEY_DOWN:
++(data->y);
--(data->height);
break;
case KEY_LEFT:
--(data->x);
++(data->width);
break;
case KEY_RIGHT:
++(data->x);
--(data->width);
break;
}
WINDOW* tmp = newwin(data->height, data->width, data->y, data->x);
WINDOW* old_win = panel_window(top);
replace_panel(top, tmp);
delwin(old_win);
// replacing panel doesn't automatically show the new window
win_show(tmp, data->label, data->label_color);
update_panels();
doupdate();
}
move(LINES-3, 0);
clrtoeol();
refresh();
update_panels();
doupdate();
}
/* Put all the windows */
void init(WINDOW **wins, PANEL **panels_arr)
{ int x, y, i;
char label[80];
PANEL_DATA* panels = (PANEL_DATA*)calloc(COUNT, sizeof(PANEL_DATA));
y = 2;
x = 10;
for(i = 0; i < COUNT; ++i)
{ wins[i] = newwin(NLINES, NCOLS, y, x);
sprintf(label, "Window Number %d", i + 1);
win_show(wins[i], label, i + 1);
// attach panels
panels_arr[i] = new_panel(wins[i]);
// create data
strcpy(panels[i].label, label);
panels[i].label_color = i+1;
panels[i].x = x;
panels[i].y = y;
panels[i].height = NLINES;
panels[i].width = NCOLS;
set_panel_userptr(panels_arr[i], &panels[i]);
// do something :)
y += 3;
x += 7;
}
panels[0].next = panels_arr[1];
panels[1].next = panels_arr[2];
panels[2].next = panels_arr[0];
}
/* Show the window with a border and a label */
void win_show(WINDOW *win, char *label, int label_color)
{ int startx, starty, maxy, maxx;
getbegyx(win, starty, startx);
getmaxyx(win, maxy, maxx);
box(win, 0, 0);
mvwaddch(win, TEELINE, 0, ACS_LTEE);
mvwhline(win, TEELINE, 1, ACS_HLINE, maxx - 2);
mvwaddch(win, TEELINE, maxx - 1, ACS_RTEE);
print_in_middle(win, maxx, TEELINE, label, COLOR_PAIR(label_color));
}
void print_in_middle(WINDOW* win, int maxx, int teeline, char *string,
chtype color)
{
int length = strlen(string);
int middle = (maxx - length) / 2;
wattron(win, color);
mvwprintw(win, teeline/2, middle, "%s", string);
wattroff(win, color);
wrefresh(win);
}
void operate_on_panel(PANEL* p)
{
WINDOW *top_win = panel_window(p);
int curs_x, curs_y;
getyx(top_win, curs_y, curs_x);
int cols = getmaxx(top_win);
wmove(top_win, TEELINE+1, 1); /* set cursor ready to write */
int c = 0;
while ((c = wgetch(top_win)) != 27) {
int x,y;
getyx(top_win, y, x);
if (x == cols-1)
wmove(top_win, y+1, 1);
waddch(top_win, c); // print what user has typed
wrefresh(top_win);
}
/* clear notice */
move(LINES-3,0);
clrtoeol();
refresh();
// return cursor back to initial position
wmove(top_win, curs_y, curs_x);
wrefresh(top_win);
}
@etzl
Copy link
Author

etzl commented Oct 25, 2020

Also if you wanted to solve a problem :) take a look at line 209-211. I couldn't put these lines inside the loop which somehow didn't initialized at runtime. I've tried if-else to set last parameter to first one and also used this line panels[i].next = panels_arr[(i+1) % COUNT] but didn't have any luck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment