From dceabff6cfc6bd6572a98b5c8f7775b42dc732a7 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Mon, 17 Nov 2014 04:41:18 +0100 Subject: renamed the "NCurses" UI to "Curses" internally * does not change ./configure parameters You still have to specifiy --with-interface=ncurses for the Curses interface with default settings * the "NCurses" UI was used for many different Curses variants, so plain "Curses" is a better name. --- src/Makefile.am | 4 +- src/interface-curses.cpp | 525 ++++++++++++++++++++++++++++++++++++++++++++++ src/interface-curses.h | 141 +++++++++++++ src/interface-ncurses.cpp | 525 ---------------------------------------------- src/interface-ncurses.h | 141 ------------- src/interface.h | 4 +- 6 files changed, 670 insertions(+), 670 deletions(-) create mode 100644 src/interface-curses.cpp create mode 100644 src/interface-curses.h delete mode 100644 src/interface-ncurses.cpp delete mode 100644 src/interface-ncurses.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 4833b6e..af324e0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,9 +45,9 @@ libsciteco_base_a_SOURCES += interface-gtk.cpp interface-gtk.h nodist_libsciteco_base_a_SOURCES += gtk-info-popup.c else -# else must be NCurses interface +# else must be Curses interface -libsciteco_base_a_SOURCES += interface-ncurses.cpp interface-ncurses.h +libsciteco_base_a_SOURCES += interface-curses.cpp interface-curses.h endif diff --git a/src/interface-curses.cpp b/src/interface-curses.cpp new file mode 100644 index 0000000..ad7296f --- /dev/null +++ b/src/interface-curses.cpp @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2012-2014 Robin Haberkorn + * + * 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 . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#ifdef EMSCRIPTEN +#include +#endif + +#include "sciteco.h" +#include "cmdline.h" +#include "qregisters.h" +#include "ring.h" +#include "interface.h" +#include "interface-curses.h" + +namespace SciTECO { + +extern "C" { +static void scintilla_notify(Scintilla *sci, int idFrom, + void *notify, void *user_data); +} + +#define UNNAMED_FILE "(Unnamed)" + +#define SCI_COLOR_ATTR(f, b) \ + ((chtype)COLOR_PAIR(SCI_COLOR_PAIR(f, b))) + +void +ViewCurses::initialize_impl(void) +{ + WINDOW *window; + + /* NOTE: Scintilla initializes color pairs */ + sci = scintilla_new(scintilla_notify); + window = get_window(); + + /* + * Window must have dimension before it can be + * positioned. + * Perhaps it's better to leave the window + * unitialized and set the position in + * InterfaceCurses::show_view(). + */ + wresize(window, 1, 1); + /* Set up window position: never changes */ + mvwin(window, 1, 0); + + setup(); +} + +void +InterfaceCurses::main_impl(int &argc, char **&argv) +{ + init_screen(); + cbreak(); + noecho(); + curs_set(0); /* Scintilla draws its own cursor */ + + setlocale(LC_CTYPE, ""); /* for displaying UTF-8 characters properly */ + + info_window = newwin(1, 0, 0, 0); + info_current = g_strdup(PACKAGE_NAME); + + msg_window = newwin(1, 0, LINES - 2, 0); + + cmdline_window = newwin(0, 0, LINES - 1, 0); + cmdline_current = NULL; + + draw_info(); + /* scintilla will be refreshed in event loop */ + msg_clear(); + cmdline_update(""); + +#ifdef EMSCRIPTEN + nodelay(cmdline_window, TRUE); +#else +#ifndef PDCURSES_WIN32A + /* workaround: endwin() is somewhat broken in the win32a port */ + endwin(); +#endif +#endif +} + +#ifdef __PDCURSES__ + +void +InterfaceCurses::init_screen(void) +{ +#ifdef PDCURSES_WIN32A + /* enables window resizing on Win32a port */ + PDC_set_resize_limits(25, 0xFFFF, 80, 0xFFFF); +#endif + + initscr(); + + screen_tty = NULL; + screen = NULL; +} + +#else + +void +InterfaceCurses::init_screen(void) +{ + /* + * Prevent the initial redraw and any escape sequences that may + * interfere with stdout, so we may use the terminal in + * cooked mode, for commandline help and batch processing. + * Scintilla must be initialized for batch processing to work. + * (Frankly I have no idea why this works!) + */ + screen_tty = g_fopen("/dev/tty", "r+b"); + screen = newterm(NULL, screen_tty, screen_tty); + set_term(screen); +} + +#endif /* !__PDCURSES__ */ + +void +InterfaceCurses::resize_all_windows(void) +{ + int lines, cols; /* screen dimensions */ + + getmaxyx(stdscr, lines, cols); + + wresize(info_window, 1, cols); + wresize(current_view->get_window(), + lines - 3, cols); + wresize(msg_window, 1, cols); + mvwin(msg_window, lines - 2, 0); + wresize(cmdline_window, 1, cols); + mvwin(cmdline_window, lines - 1, 0); + + draw_info(); + /* scintilla will be refreshed in event loop */ + msg_clear(); /* FIXME: use saved message */ + cmdline_update(); +} + +void +InterfaceCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap) +{ + static const chtype type2attr[] = { + SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE), /* MSG_USER */ + SCI_COLOR_ATTR(COLOR_BLACK, COLOR_GREEN), /* MSG_INFO */ + SCI_COLOR_ATTR(COLOR_BLACK, COLOR_YELLOW), /* MSG_WARNING */ + SCI_COLOR_ATTR(COLOR_BLACK, COLOR_RED) /* MSG_ERROR */ + }; + +#ifdef PDCURSES_WIN32A + stdio_vmsg(type, fmt, ap); + if (isendwin()) /* batch mode */ + return; +#else + if (isendwin()) { /* batch mode */ + stdio_vmsg(type, fmt, ap); + return; + } +#endif + + wmove(msg_window, 0, 0); + wbkgdset(msg_window, ' ' | type2attr[type]); + vw_printw(msg_window, fmt, ap); + wclrtoeol(msg_window); + + wrefresh(msg_window); +} + +void +InterfaceCurses::msg_clear(void) +{ + if (isendwin()) /* batch mode */ + return; + + wmove(msg_window, 0, 0); + wbkgdset(msg_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE)); + wclrtoeol(msg_window); + + wrefresh(msg_window); +} + +void +InterfaceCurses::show_view_impl(ViewCurses *view) +{ + int lines, cols; /* screen dimensions */ + + current_view = view; + + /* + * screen size might have changed since + * this view's WINDOW was last active + */ + getmaxyx(stdscr, lines, cols); + wresize(current_view->get_window(), + lines - 3, cols); +} + +void +InterfaceCurses::draw_info(void) +{ + if (isendwin()) /* batch mode */ + return; + + wmove(info_window, 0, 0); + wbkgdset(info_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE)); + waddstr(info_window, info_current); + wclrtoeol(info_window); + + wrefresh(info_window); +} + +void +InterfaceCurses::info_update_impl(QRegister *reg) +{ + g_free(info_current); + info_current = g_strdup_printf("%s - %s", PACKAGE_NAME, + reg->name); + + draw_info(); +} + +void +InterfaceCurses::info_update_impl(Buffer *buffer) +{ + g_free(info_current); + info_current = g_strdup_printf("%s - %s%s", PACKAGE_NAME, + buffer->filename ? : UNNAMED_FILE, + buffer->dirty ? "*" : ""); + + draw_info(); +} + +void +InterfaceCurses::cmdline_update_impl(const gchar *cmdline) +{ + size_t len; + int half_line = (getmaxx(stdscr) - 2) / 2; + const gchar *line; + + if (cmdline) { + g_free(cmdline_current); + cmdline_current = g_strdup(cmdline); + } else { + cmdline = cmdline_current; + } + len = strlen(cmdline); + + /* FIXME: optimize */ + line = cmdline + len - MIN(len, half_line + len % half_line); + + mvwaddch(cmdline_window, 0, 0, '*'); + waddstr(cmdline_window, line); + waddch(cmdline_window, ' ' | A_REVERSE); + wclrtoeol(cmdline_window); + + wrefresh(cmdline_window); +} + +void +InterfaceCurses::popup_add_impl(PopupEntryType type, + const gchar *name, bool highlight) +{ + gchar *entry; + + if (isendwin()) /* batch mode */ + return; + + entry = g_strconcat(highlight ? "*" : " ", name, NIL); + + popup.longest = MAX(popup.longest, (gint)strlen(name)); + popup.length++; + + popup.list = g_slist_prepend(popup.list, entry); +} + +void +InterfaceCurses::popup_show_impl(void) +{ + int lines, cols; /* screen dimensions */ + int popup_lines; + gint popup_cols; + gint cur_file, cur_line; + + if (isendwin()) /* batch mode */ + goto cleanup; + + getmaxyx(stdscr, lines, cols); + + popup.longest += 3; + popup.list = g_slist_reverse(popup.list); + + /* popup_cols = floor(cols / popup.longest) */ + popup_cols = MAX(cols / popup.longest, 1); + /* popup_lines = ceil(popup.length / popup_cols) */ + popup_lines = popup.length / popup_cols; + if ((popup.length % popup_cols)) + popup_lines++; + popup_lines = MIN(popup_lines, lines - 1); + + /* window covers message, scintilla and info windows */ + popup.window = newwin(popup_lines, 0, lines - 1 - popup_lines, 0); + wbkgdset(popup.window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_BLUE)); + + cur_file = 0; + cur_line = 1; + for (GSList *cur = popup.list; cur; cur = g_slist_next(cur)) { + gchar *entry = (gchar *)cur->data; + + if (cur_file && !(cur_file % popup_cols)) { + wclrtoeol(popup.window); + waddch(popup.window, '\n'); + cur_line++; + } + + cur_file++; + + if (cur_line == popup_lines && !(cur_file % popup_cols) && + cur_file < popup.length) { + (void)wattrset(popup.window, A_BOLD); + waddstr(popup.window, "..."); + break; + } + + (void)wattrset(popup.window, *entry == '*' ? A_BOLD : A_NORMAL); + waddstr(popup.window, entry + 1); + for (int i = popup.longest - strlen(entry) + 1; i; i--) + waddch(popup.window, ' '); + + g_free(cur->data); + } + wclrtoeol(popup.window); + +cleanup: + g_slist_free(popup.list); + popup.list = NULL; + popup.longest = popup.length = 0; +} + +void +InterfaceCurses::popup_clear_impl(void) +{ + if (!popup.window) + return; + + redrawwin(info_window); + wrefresh(info_window); + redrawwin(current_view->get_window()); + current_view->refresh(); + redrawwin(msg_window); + wrefresh(msg_window); + + delwin(popup.window); + popup.window = NULL; +} + +/** + * One iteration of the event loop. + * + * This is a global function, so it may + * be used as an Emscripten callback. + * + * @bug + * Can probably be defined as a static method, + * so we can avoid declaring it a fried function of + * InterfaceCurses. + */ +void +event_loop_iter() +{ + int key; + + keypad(interface.cmdline_window, Flags::ed & Flags::ED_FNKEYS); + + /* no special handling */ + raw(); + key = wgetch(interface.cmdline_window); + /* allow asynchronous interruptions on */ + cbreak(); + if (key == ERR) + return; + + switch (key) { +#ifdef KEY_RESIZE + case KEY_RESIZE: +#ifdef PDCURSES + resize_term(0, 0); +#endif + interface.resize_all_windows(); + break; +#endif + case 0x7F: /* DEL */ + case KEY_BACKSPACE: + cmdline_keypress('\b'); + break; + case KEY_ENTER: + case '\r': + case '\n': + cmdline_keypress(get_eol()); + break; + + /* + * Function key macros + */ +#define FN(KEY) case KEY_##KEY: cmdline_fnmacro(#KEY); break +#define FNS(KEY) FN(KEY); FN(S##KEY) + FN(DOWN); FN(UP); FNS(LEFT); FNS(RIGHT); + FNS(HOME); + case KEY_F(0)...KEY_F(63): { + gchar macro_name[3+1]; + + g_snprintf(macro_name, sizeof(macro_name), + "F%d", key - KEY_F0); + cmdline_fnmacro(macro_name); + break; + } + FNS(DC); + FNS(IC); + FN(NPAGE); FN(PPAGE); + FNS(PRINT); + FN(A1); FN(A3); FN(B2); FN(C1); FN(C3); + FNS(END); + FNS(HELP); +#undef FNS +#undef FN + + /* + * Control keys and keys with printable representation + */ + default: + if (key <= 0xFF) + cmdline_keypress((gchar)key); + } + + sigint_occurred = FALSE; + + interface.current_view->refresh(); + if (interface.popup.window) + wrefresh(interface.popup.window); +} + +void +InterfaceCurses::event_loop_impl(void) +{ + /* initial refresh: window might have been changed in batch mode */ + current_view->refresh(); + draw_info(); + +#ifdef EMSCRIPTEN + PDC_emscripten_set_handler(event_loop_iter, TRUE); +#else + for (;;) + event_loop_iter(); +#endif +} + +InterfaceCurses::Popup::~Popup() +{ + if (window) + delwin(window); + if (list) + g_slist_free(list); +} + +InterfaceCurses::~InterfaceCurses() +{ + if (info_window) + delwin(info_window); + g_free(info_current); + if (cmdline_window) + delwin(cmdline_window); + g_free(cmdline_current); + if (msg_window) + delwin(msg_window); + + if (!isendwin()) + endwin(); + + if (screen) + delscreen(screen); + if (screen_tty) + fclose(screen_tty); +} + +/* + * Callbacks + */ + +static void +scintilla_notify(Scintilla *sci, int idFrom, void *notify, void *user_data) +{ + interface.process_notify((SCNotification *)notify); +} + +} /* namespace SciTECO */ diff --git a/src/interface-curses.h b/src/interface-curses.h new file mode 100644 index 0000000..35f7edb --- /dev/null +++ b/src/interface-curses.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2012-2014 Robin Haberkorn + * + * 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 . + */ + +#ifndef __INTERFACE_CURSES_H +#define __INTERFACE_CURSES_H + +#include + +#include + +#include + +#include +#include + +#include "interface.h" + +namespace SciTECO { + +typedef class ViewCurses : public View { + Scintilla *sci; + +public: + ViewCurses() : sci(NULL) {} + + /* implementation of View::initialize() */ + void initialize_impl(void); + + inline ~ViewCurses() + { + if (sci) { + delwin(get_window()); + scintilla_delete(sci); + } + } + + inline void + refresh(void) + { + scintilla_refresh(sci); + } + + inline WINDOW * + get_window(void) + { + return scintilla_get_window(sci); + } + + /* implementation of View::ssm() */ + inline sptr_t + ssm_impl(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0) + { + return scintilla_send_message(sci, iMessage, wParam, lParam); + } +} ViewCurrent; + +typedef class InterfaceCurses : public Interface { + SCREEN *screen; + FILE *screen_tty; + + WINDOW *info_window; + gchar *info_current; + WINDOW *msg_window; + WINDOW *cmdline_window; + gchar *cmdline_current; + + struct Popup { + WINDOW *window; + GSList *list; + gint longest; + gint length; + + Popup() : window(NULL), list(NULL), longest(0), length(0) {} + ~Popup(); + } popup; + +public: + InterfaceCurses() : Interface(), + screen(NULL), + screen_tty(NULL), + info_window(NULL), + info_current(NULL), + msg_window(NULL), + cmdline_window(NULL), + cmdline_current(NULL) {} + ~InterfaceCurses(); + + /* implementation of Interface::main() */ + void main_impl(int &argc, char **&argv); + + /* implementation of Interface::vmsg() */ + void vmsg_impl(MessageType type, const gchar *fmt, va_list ap); + /* override of Interface::msg_clear() */ + void msg_clear(void); + + /* implementation of Interface::show_view() */ + void show_view_impl(ViewCurses *view); + + /* implementation of Interface::info_update() */ + void info_update_impl(QRegister *reg); + void info_update_impl(Buffer *buffer); + + /* implementation of Interface::cmdline_update() */ + void cmdline_update_impl(const gchar *cmdline = NULL); + + /* implementation of Interface::popup_add() */ + void popup_add_impl(PopupEntryType type, + const gchar *name, bool highlight = false); + /* implementation of Interface::popup_show() */ + void popup_show_impl(void); + /* implementation of Interface::popup_clear() */ + void popup_clear_impl(void); + + /* main entry point (implementation) */ + void event_loop_impl(void); + +private: + void init_screen(void); + void resize_all_windows(void); + void draw_info(void); + + friend void event_loop_iter(); +} InterfaceCurrent; + +} /* namespace SciTECO */ + +#endif diff --git a/src/interface-ncurses.cpp b/src/interface-ncurses.cpp deleted file mode 100644 index 32c310c..0000000 --- a/src/interface-ncurses.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright (C) 2012-2014 Robin Haberkorn - * - * 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 . - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#ifdef EMSCRIPTEN -#include -#endif - -#include "sciteco.h" -#include "cmdline.h" -#include "qregisters.h" -#include "ring.h" -#include "interface.h" -#include "interface-ncurses.h" - -namespace SciTECO { - -extern "C" { -static void scintilla_notify(Scintilla *sci, int idFrom, - void *notify, void *user_data); -} - -#define UNNAMED_FILE "(Unnamed)" - -#define SCI_COLOR_ATTR(f, b) \ - ((chtype)COLOR_PAIR(SCI_COLOR_PAIR(f, b))) - -void -ViewNCurses::initialize_impl(void) -{ - WINDOW *window; - - /* NOTE: Scintilla initializes color pairs */ - sci = scintilla_new(scintilla_notify); - window = get_window(); - - /* - * Window must have dimension before it can be - * positioned. - * Perhaps it's better to leave the window - * unitialized and set the position in - * InterfaceNCurses::show_view(). - */ - wresize(window, 1, 1); - /* Set up window position: never changes */ - mvwin(window, 1, 0); - - setup(); -} - -void -InterfaceNCurses::main_impl(int &argc, char **&argv) -{ - init_screen(); - cbreak(); - noecho(); - curs_set(0); /* Scintilla draws its own cursor */ - - setlocale(LC_CTYPE, ""); /* for displaying UTF-8 characters properly */ - - info_window = newwin(1, 0, 0, 0); - info_current = g_strdup(PACKAGE_NAME); - - msg_window = newwin(1, 0, LINES - 2, 0); - - cmdline_window = newwin(0, 0, LINES - 1, 0); - cmdline_current = NULL; - - draw_info(); - /* scintilla will be refreshed in event loop */ - msg_clear(); - cmdline_update(""); - -#ifdef EMSCRIPTEN - nodelay(cmdline_window, TRUE); -#else -#ifndef PDCURSES_WIN32A - /* workaround: endwin() is somewhat broken in the win32a port */ - endwin(); -#endif -#endif -} - -#ifdef __PDCURSES__ - -void -InterfaceNCurses::init_screen(void) -{ -#ifdef PDCURSES_WIN32A - /* enables window resizing on Win32a port */ - PDC_set_resize_limits(25, 0xFFFF, 80, 0xFFFF); -#endif - - initscr(); - - screen_tty = NULL; - screen = NULL; -} - -#else - -void -InterfaceNCurses::init_screen(void) -{ - /* - * Prevent the initial redraw and any escape sequences that may - * interfere with stdout, so we may use the terminal in - * cooked mode, for commandline help and batch processing. - * Scintilla must be initialized for batch processing to work. - * (Frankly I have no idea why this works!) - */ - screen_tty = g_fopen("/dev/tty", "r+b"); - screen = newterm(NULL, screen_tty, screen_tty); - set_term(screen); -} - -#endif /* !__PDCURSES__ */ - -void -InterfaceNCurses::resize_all_windows(void) -{ - int lines, cols; /* screen dimensions */ - - getmaxyx(stdscr, lines, cols); - - wresize(info_window, 1, cols); - wresize(current_view->get_window(), - lines - 3, cols); - wresize(msg_window, 1, cols); - mvwin(msg_window, lines - 2, 0); - wresize(cmdline_window, 1, cols); - mvwin(cmdline_window, lines - 1, 0); - - draw_info(); - /* scintilla will be refreshed in event loop */ - msg_clear(); /* FIXME: use saved message */ - cmdline_update(); -} - -void -InterfaceNCurses::vmsg_impl(MessageType type, const gchar *fmt, va_list ap) -{ - static const chtype type2attr[] = { - SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE), /* MSG_USER */ - SCI_COLOR_ATTR(COLOR_BLACK, COLOR_GREEN), /* MSG_INFO */ - SCI_COLOR_ATTR(COLOR_BLACK, COLOR_YELLOW), /* MSG_WARNING */ - SCI_COLOR_ATTR(COLOR_BLACK, COLOR_RED) /* MSG_ERROR */ - }; - -#ifdef PDCURSES_WIN32A - stdio_vmsg(type, fmt, ap); - if (isendwin()) /* batch mode */ - return; -#else - if (isendwin()) { /* batch mode */ - stdio_vmsg(type, fmt, ap); - return; - } -#endif - - wmove(msg_window, 0, 0); - wbkgdset(msg_window, ' ' | type2attr[type]); - vw_printw(msg_window, fmt, ap); - wclrtoeol(msg_window); - - wrefresh(msg_window); -} - -void -InterfaceNCurses::msg_clear(void) -{ - if (isendwin()) /* batch mode */ - return; - - wmove(msg_window, 0, 0); - wbkgdset(msg_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE)); - wclrtoeol(msg_window); - - wrefresh(msg_window); -} - -void -InterfaceNCurses::show_view_impl(ViewNCurses *view) -{ - int lines, cols; /* screen dimensions */ - - current_view = view; - - /* - * screen size might have changed since - * this view's WINDOW was last active - */ - getmaxyx(stdscr, lines, cols); - wresize(current_view->get_window(), - lines - 3, cols); -} - -void -InterfaceNCurses::draw_info(void) -{ - if (isendwin()) /* batch mode */ - return; - - wmove(info_window, 0, 0); - wbkgdset(info_window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_WHITE)); - waddstr(info_window, info_current); - wclrtoeol(info_window); - - wrefresh(info_window); -} - -void -InterfaceNCurses::info_update_impl(QRegister *reg) -{ - g_free(info_current); - info_current = g_strdup_printf("%s - %s", PACKAGE_NAME, - reg->name); - - draw_info(); -} - -void -InterfaceNCurses::info_update_impl(Buffer *buffer) -{ - g_free(info_current); - info_current = g_strdup_printf("%s - %s%s", PACKAGE_NAME, - buffer->filename ? : UNNAMED_FILE, - buffer->dirty ? "*" : ""); - - draw_info(); -} - -void -InterfaceNCurses::cmdline_update_impl(const gchar *cmdline) -{ - size_t len; - int half_line = (getmaxx(stdscr) - 2) / 2; - const gchar *line; - - if (cmdline) { - g_free(cmdline_current); - cmdline_current = g_strdup(cmdline); - } else { - cmdline = cmdline_current; - } - len = strlen(cmdline); - - /* FIXME: optimize */ - line = cmdline + len - MIN(len, half_line + len % half_line); - - mvwaddch(cmdline_window, 0, 0, '*'); - waddstr(cmdline_window, line); - waddch(cmdline_window, ' ' | A_REVERSE); - wclrtoeol(cmdline_window); - - wrefresh(cmdline_window); -} - -void -InterfaceNCurses::popup_add_impl(PopupEntryType type, - const gchar *name, bool highlight) -{ - gchar *entry; - - if (isendwin()) /* batch mode */ - return; - - entry = g_strconcat(highlight ? "*" : " ", name, NIL); - - popup.longest = MAX(popup.longest, (gint)strlen(name)); - popup.length++; - - popup.list = g_slist_prepend(popup.list, entry); -} - -void -InterfaceNCurses::popup_show_impl(void) -{ - int lines, cols; /* screen dimensions */ - int popup_lines; - gint popup_cols; - gint cur_file, cur_line; - - if (isendwin()) /* batch mode */ - goto cleanup; - - getmaxyx(stdscr, lines, cols); - - popup.longest += 3; - popup.list = g_slist_reverse(popup.list); - - /* popup_cols = floor(cols / popup.longest) */ - popup_cols = MAX(cols / popup.longest, 1); - /* popup_lines = ceil(popup.length / popup_cols) */ - popup_lines = popup.length / popup_cols; - if ((popup.length % popup_cols)) - popup_lines++; - popup_lines = MIN(popup_lines, lines - 1); - - /* window covers message, scintilla and info windows */ - popup.window = newwin(popup_lines, 0, lines - 1 - popup_lines, 0); - wbkgdset(popup.window, ' ' | SCI_COLOR_ATTR(COLOR_BLACK, COLOR_BLUE)); - - cur_file = 0; - cur_line = 1; - for (GSList *cur = popup.list; cur; cur = g_slist_next(cur)) { - gchar *entry = (gchar *)cur->data; - - if (cur_file && !(cur_file % popup_cols)) { - wclrtoeol(popup.window); - waddch(popup.window, '\n'); - cur_line++; - } - - cur_file++; - - if (cur_line == popup_lines && !(cur_file % popup_cols) && - cur_file < popup.length) { - (void)wattrset(popup.window, A_BOLD); - waddstr(popup.window, "..."); - break; - } - - (void)wattrset(popup.window, *entry == '*' ? A_BOLD : A_NORMAL); - waddstr(popup.window, entry + 1); - for (int i = popup.longest - strlen(entry) + 1; i; i--) - waddch(popup.window, ' '); - - g_free(cur->data); - } - wclrtoeol(popup.window); - -cleanup: - g_slist_free(popup.list); - popup.list = NULL; - popup.longest = popup.length = 0; -} - -void -InterfaceNCurses::popup_clear_impl(void) -{ - if (!popup.window) - return; - - redrawwin(info_window); - wrefresh(info_window); - redrawwin(current_view->get_window()); - current_view->refresh(); - redrawwin(msg_window); - wrefresh(msg_window); - - delwin(popup.window); - popup.window = NULL; -} - -/** - * One iteration of the event loop. - * - * This is a global function, so it may - * be used as an Emscripten callback. - * - * @bug - * Can probably be defined as a static method, - * so we can avoid declaring it a fried function of - * InterfaceNCurses. - */ -void -event_loop_iter() -{ - int key; - - keypad(interface.cmdline_window, Flags::ed & Flags::ED_FNKEYS); - - /* no special handling */ - raw(); - key = wgetch(interface.cmdline_window); - /* allow asynchronous interruptions on */ - cbreak(); - if (key == ERR) - return; - - switch (key) { -#ifdef KEY_RESIZE - case KEY_RESIZE: -#ifdef PDCURSES - resize_term(0, 0); -#endif - interface.resize_all_windows(); - break; -#endif - case 0x7F: /* DEL */ - case KEY_BACKSPACE: - cmdline_keypress('\b'); - break; - case KEY_ENTER: - case '\r': - case '\n': - cmdline_keypress(get_eol()); - break; - - /* - * Function key macros - */ -#define FN(KEY) case KEY_##KEY: cmdline_fnmacro(#KEY); break -#define FNS(KEY) FN(KEY); FN(S##KEY) - FN(DOWN); FN(UP); FNS(LEFT); FNS(RIGHT); - FNS(HOME); - case KEY_F(0)...KEY_F(63): { - gchar macro_name[3+1]; - - g_snprintf(macro_name, sizeof(macro_name), - "F%d", key - KEY_F0); - cmdline_fnmacro(macro_name); - break; - } - FNS(DC); - FNS(IC); - FN(NPAGE); FN(PPAGE); - FNS(PRINT); - FN(A1); FN(A3); FN(B2); FN(C1); FN(C3); - FNS(END); - FNS(HELP); -#undef FNS -#undef FN - - /* - * Control keys and keys with printable representation - */ - default: - if (key <= 0xFF) - cmdline_keypress((gchar)key); - } - - sigint_occurred = FALSE; - - interface.current_view->refresh(); - if (interface.popup.window) - wrefresh(interface.popup.window); -} - -void -InterfaceNCurses::event_loop_impl(void) -{ - /* initial refresh: window might have been changed in batch mode */ - current_view->refresh(); - draw_info(); - -#ifdef EMSCRIPTEN - PDC_emscripten_set_handler(event_loop_iter, TRUE); -#else - for (;;) - event_loop_iter(); -#endif -} - -InterfaceNCurses::Popup::~Popup() -{ - if (window) - delwin(window); - if (list) - g_slist_free(list); -} - -InterfaceNCurses::~InterfaceNCurses() -{ - if (info_window) - delwin(info_window); - g_free(info_current); - if (cmdline_window) - delwin(cmdline_window); - g_free(cmdline_current); - if (msg_window) - delwin(msg_window); - - if (!isendwin()) - endwin(); - - if (screen) - delscreen(screen); - if (screen_tty) - fclose(screen_tty); -} - -/* - * Callbacks - */ - -static void -scintilla_notify(Scintilla *sci, int idFrom, void *notify, void *user_data) -{ - interface.process_notify((SCNotification *)notify); -} - -} /* namespace SciTECO */ diff --git a/src/interface-ncurses.h b/src/interface-ncurses.h deleted file mode 100644 index 53b6b3e..0000000 --- a/src/interface-ncurses.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2012-2014 Robin Haberkorn - * - * 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 . - */ - -#ifndef __INTERFACE_NCURSES_H -#define __INTERFACE_NCURSES_H - -#include - -#include - -#include - -#include -#include - -#include "interface.h" - -namespace SciTECO { - -typedef class ViewNCurses : public View { - Scintilla *sci; - -public: - ViewNCurses() : sci(NULL) {} - - /* implementation of View::initialize() */ - void initialize_impl(void); - - inline ~ViewNCurses() - { - if (sci) { - delwin(get_window()); - scintilla_delete(sci); - } - } - - inline void - refresh(void) - { - scintilla_refresh(sci); - } - - inline WINDOW * - get_window(void) - { - return scintilla_get_window(sci); - } - - /* implementation of View::ssm() */ - inline sptr_t - ssm_impl(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0) - { - return scintilla_send_message(sci, iMessage, wParam, lParam); - } -} ViewCurrent; - -typedef class InterfaceNCurses : public Interface { - SCREEN *screen; - FILE *screen_tty; - - WINDOW *info_window; - gchar *info_current; - WINDOW *msg_window; - WINDOW *cmdline_window; - gchar *cmdline_current; - - struct Popup { - WINDOW *window; - GSList *list; - gint longest; - gint length; - - Popup() : window(NULL), list(NULL), longest(0), length(0) {} - ~Popup(); - } popup; - -public: - InterfaceNCurses() : Interface(), - screen(NULL), - screen_tty(NULL), - info_window(NULL), - info_current(NULL), - msg_window(NULL), - cmdline_window(NULL), - cmdline_current(NULL) {} - ~InterfaceNCurses(); - - /* implementation of Interface::main() */ - void main_impl(int &argc, char **&argv); - - /* implementation of Interface::vmsg() */ - void vmsg_impl(MessageType type, const gchar *fmt, va_list ap); - /* override of Interface::msg_clear() */ - void msg_clear(void); - - /* implementation of Interface::show_view() */ - void show_view_impl(ViewNCurses *view); - - /* implementation of Interface::info_update() */ - void info_update_impl(QRegister *reg); - void info_update_impl(Buffer *buffer); - - /* implementation of Interface::cmdline_update() */ - void cmdline_update_impl(const gchar *cmdline = NULL); - - /* implementation of Interface::popup_add() */ - void popup_add_impl(PopupEntryType type, - const gchar *name, bool highlight = false); - /* implementation of Interface::popup_show() */ - void popup_show_impl(void); - /* implementation of Interface::popup_clear() */ - void popup_clear_impl(void); - - /* main entry point (implementation) */ - void event_loop_impl(void); - -private: - void init_screen(void); - void resize_all_windows(void); - void draw_info(void); - - friend void event_loop_iter(); -} InterfaceCurrent; - -} /* namespace SciTECO */ - -#endif diff --git a/src/interface.h b/src/interface.h index 8fa0112..a883a5f 100644 --- a/src/interface.h +++ b/src/interface.h @@ -327,8 +327,8 @@ public: #ifdef INTERFACE_GTK #include "interface-gtk.h" -#elif defined(INTERFACE_NCURSES) -#include "interface-ncurses.h" +#elif defined(INTERFACE_CURSES) +#include "interface-curses.h" #else #error No interface selected! #endif -- cgit v1.2.3