diff --git a/Makefile.am b/Makefile.am index 03d2f1d96..3fe41a449 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,5 @@ SUBDIRS = \ main \ - @ncurses_dir@ \ @bzlib2_dir@ \ @zlib_dir@ \ @mysql_dir@ \ @@ -27,6 +26,7 @@ SUBDIRS = \ @imageimlib_dir@ \ @dbus_dir@ \ @gsl_dir@ \ + @ncurses_dir@ \ comp \ app \ examples \ diff --git a/configure.ac b/configure.ac index 671fdf871..56fb1b991 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,6 @@ AC_INIT(configure.ac) AC_CONFIG_SUBDIRS(main) -GB_CONFIG_SUBDIRS(ncurses, gb.ncurses) GB_CONFIG_SUBDIRS(bzlib2, gb.compress.bzlib2) GB_CONFIG_SUBDIRS(zlib, gb.compress.zlib) GB_CONFIG_SUBDIRS(mysql, gb.db.mysql) @@ -36,6 +35,7 @@ GB_CONFIG_SUBDIRS(imageio, gb.image.io) GB_CONFIG_SUBDIRS(imageimlib, gb.image.imlib) GB_CONFIG_SUBDIRS(dbus, gb.dbus) GB_CONFIG_SUBDIRS(gsl, gb.gsl) +GB_CONFIG_SUBDIRS(ncurses, gb.ncurses) AC_CONFIG_SUBDIRS(comp) AC_CONFIG_SUBDIRS(app) diff --git a/gb.ncurses/src/Makefile.am b/gb.ncurses/src/Makefile.am index fbf624244..22b7777fc 100644 --- a/gb.ncurses/src/Makefile.am +++ b/gb.ncurses/src/Makefile.am @@ -11,5 +11,6 @@ gb_ncurses_la_LDFLAGS = -module @LD_FLAGS@ @NCURSES_LDFLAGS@ gb_ncurses_la_SOURCES = \ main.h main.c \ c_ncurses.h c_ncurses.c \ - c_window.h c_window.c + c_window.h c_window.c \ + c_key.h c_key.c diff --git a/gb.ncurses/src/c_key.c b/gb.ncurses/src/c_key.c new file mode 100644 index 000000000..ea6b46cc0 --- /dev/null +++ b/gb.ncurses/src/c_key.c @@ -0,0 +1,65 @@ +/* + * c_key.c - gb.ncurses Key static class + * + * Copyright (C) 2012 Tobias Boege + * + * 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 2, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#define __C_KEY_C + +#include "../gambas.h" + +#include + +#include "c_key.h" + +GB_DESC CKeyDesc[] = +{ + GB_DECLARE("Key", 0), + GB_NOT_CREATABLE(), + + GB_CONSTANT("Return", "i", (int) '\n'), + + GB_CONSTANT("Break", "i", KEY_BREAK), + GB_CONSTANT("Home", "i", KEY_HOME), + GB_CONSTANT("Backspace", "i", KEY_BACKSPACE), + GB_CONSTANT("PageUp", "i", KEY_PPAGE), + GB_CONSTANT("PageDown", "i", KEY_NPAGE), + GB_CONSTANT("Enter", "i", KEY_ENTER), + + /* Arrow Keys */ + GB_CONSTANT("Left", "i", KEY_LEFT), + GB_CONSTANT("Right", "i", KEY_RIGHT), + GB_CONSTANT("Up", "i", KEY_UP), + GB_CONSTANT("Down", "i", KEY_DOWN), + + /* F keys */ + GB_CONSTANT("F1", "i", KEY_F(0)), + GB_CONSTANT("F2", "i", KEY_F(1)), + GB_CONSTANT("F3", "i", KEY_F(2)), + GB_CONSTANT("F4", "i", KEY_F(3)), + GB_CONSTANT("F5", "i", KEY_F(4)), + GB_CONSTANT("F6", "i", KEY_F(5)), + GB_CONSTANT("F7", "i", KEY_F(6)), + GB_CONSTANT("F8", "i", KEY_F(7)), + GB_CONSTANT("F9", "i", KEY_F(8)), + GB_CONSTANT("F10", "i", KEY_F(9)), + GB_CONSTANT("F11", "i", KEY_F(10)), + GB_CONSTANT("F12", "i", KEY_F(11)), + + GB_END_DECLARE +}; diff --git a/gb.ncurses/src/c_key.h b/gb.ncurses/src/c_key.h new file mode 100644 index 000000000..c32b2b3ed --- /dev/null +++ b/gb.ncurses/src/c_key.h @@ -0,0 +1,29 @@ +/* + * c_key.h - gb.ncurses Key static class + * + * Copyright (C) 2012 Tobias Boege + * + * 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 2, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __C_KEY_H +#define __C_KEY_H + +#ifndef __C_KEY_C +extern GB_DESC CKeyDesc[]; +#endif + +#endif /* __C_KEY_H */ diff --git a/gb.ncurses/src/c_ncurses.c b/gb.ncurses/src/c_ncurses.c index 564de7dc2..6c08c3aac 100644 --- a/gb.ncurses/src/c_ncurses.c +++ b/gb.ncurses/src/c_ncurses.c @@ -45,6 +45,7 @@ static int nc_echo; DECLARE_EVENT(EVENT_Resize); +#if 0 /* * Signal handler for the SIGWINCH signal. * @signum: signal number given @@ -53,12 +54,13 @@ DECLARE_EVENT(EVENT_Resize); void nc_sigwinch_handler(int signum) { /* TODO: I wonder if this works... */ - + /* BM: Of course not! :-) You can't raise an event from a signal handler * and moreover you have no sender! */ - + if (signum == SIGWINCH) GB.Raise(NULL, EVENT_Resize, 0); } +#endif static bool _init = FALSE; @@ -69,12 +71,11 @@ bool NCURSES_running() void NCURSES_init(void) { - struct sigaction sa; - if (_init) return; - + initscr(); + keypad(stdscr, TRUE); /* global variable default setup */ nc_cursor = CURSOR_VISIBLE; @@ -85,6 +86,9 @@ void NCURSES_init(void) cbreak(); noecho(); +#if 0 + struct sigaction sa; + sa.sa_handler = nc_sigwinch_handler; sigemptyset(&(sa.sa_mask)); sa.sa_flags = 0; @@ -92,9 +96,10 @@ void NCURSES_init(void) { fprintf(stderr, "gb.ncurses: Could not install SIGWINCH signal handler"); } +#endif refresh(); - + _init = TRUE; } @@ -108,7 +113,7 @@ void NCURSES_exit() } -BEGIN_PROPERTY(CNCurses_cursor) +BEGIN_PROPERTY(NCurses_Cursor) if (READ_PROPERTY) { @@ -116,7 +121,6 @@ BEGIN_PROPERTY(CNCurses_cursor) return; } - /* Hide if setting cursor is not supported */ switch (VPROP(GB_INTEGER)) { case CURSOR_HIDDEN: @@ -133,7 +137,7 @@ BEGIN_PROPERTY(CNCurses_cursor) END_PROPERTY -BEGIN_PROPERTY(CNCurses_input) +BEGIN_PROPERTY(NCurses_Input) if (READ_PROPERTY) { @@ -161,7 +165,7 @@ BEGIN_PROPERTY(CNCurses_input) END_PROPERTY -BEGIN_PROPERTY(CNCurses_echo) +BEGIN_PROPERTY(NCurses_Echo) if (READ_PROPERTY) { @@ -175,38 +179,19 @@ BEGIN_PROPERTY(CNCurses_echo) END_PROPERTY -BEGIN_PROPERTY(CNCurses_lines) +BEGIN_PROPERTY(NCurses_Lines) GB.ReturnInteger(LINES); END_PROPERTY -BEGIN_PROPERTY(CNCurses_cols) +BEGIN_PROPERTY(NCurses_Cols) GB.ReturnInteger(COLS); END_PROPERTY -BEGIN_METHOD_VOID(CNCurses_init) - - NCURSES_init(); - -END_METHOD - -BEGIN_METHOD_VOID(CNCurses_exit) - - NCURSES_exit(); - -END_METHOD - -BEGIN_METHOD_VOID(CNCurses_on) - - if (NCURSES_RUNNING) return; - refresh(); - -END_METHOD - -BEGIN_METHOD_VOID(CNCurses_off) +BEGIN_METHOD_VOID(NCurses_exit) NCURSES_exit(); @@ -224,17 +209,14 @@ GB_DESC CNCursesDesc[] = GB_CONSTANT("CBreak", "i", INPUT_CBREAK), GB_CONSTANT("Raw", "i", INPUT_RAW), - GB_STATIC_PROPERTY("Cursor", "i", CNCurses_cursor), - GB_STATIC_PROPERTY("Input", "i", CNCurses_input), - GB_STATIC_PROPERTY("Echo", "b", CNCurses_echo), + GB_STATIC_PROPERTY("Cursor", "i", NCurses_Cursor), + GB_STATIC_PROPERTY("Input", "i", NCurses_Input), + GB_STATIC_PROPERTY("Echo", "b", NCurses_Echo), - GB_STATIC_PROPERTY_READ("Lines", "i", CNCurses_lines), - GB_STATIC_PROPERTY_READ("Cols", "i", CNCurses_cols), + GB_STATIC_PROPERTY_READ("Lines", "i", NCurses_Lines), + GB_STATIC_PROPERTY_READ("Cols", "i", NCurses_Cols), - GB_STATIC_METHOD("_init", NULL, CNCurses_init, NULL), - GB_STATIC_METHOD("_exit", NULL, CNCurses_exit, NULL), - GB_STATIC_METHOD("On", NULL, CNCurses_on, NULL), - GB_STATIC_METHOD("Off", NULL, CNCurses_off, NULL), + GB_STATIC_METHOD("_exit", NULL, NCurses_exit, NULL), GB_END_DECLARE }; diff --git a/gb.ncurses/src/c_window.c b/gb.ncurses/src/c_window.c index 62df69160..1d4f0172e 100644 --- a/gb.ncurses/src/c_window.c +++ b/gb.ncurses/src/c_window.c @@ -34,13 +34,12 @@ #include "c_window.h" /* The nc_window currently having the focus (raising Read events) */ -static struct nc_window *focussed; +static struct nc_window *focused = NULL; DECLARE_EVENT(EVENT_Read); -//DECLARE_EVENT(EVENT_Redraw); /* - * C NCurses interface + * C Window interface * @_object: Reference to the struct nc_window representing the current object. * * The theory: Each struct nc_window has a main and a content window pointer. The main window @@ -66,13 +65,25 @@ DECLARE_EVENT(EVENT_Read); #define E_COORDS "Coordinates out of range" #define E_DIMENSION "Dimensions do not fit on screen" -void WINDOW_refresh() +/* + * Redraw the screen no matter what particular buffering settings the windows have. + * Note that this function may not be used to return into ncurses mode once left. + */ +void WINDOW_real_refresh() { if (!NCURSES_running()) return; update_panels(); doupdate(); } +/** + * Refresh the screen. This respects THIS' buffering wishes + */ +void WINDOW_refresh(void *_object) +{ + if (!IS_BUFFERED) + WINDOW_real_refresh(); +} /** * Copies text with attributes from a window to a newly malloced array as if the window @@ -83,7 +94,7 @@ void WINDOW_refresh() * @y: y position to start * @len: number of characters to read */ -static int nc_window_get_mem(WINDOW *src, chtype **arrp, int sx, int sy, int len) +static int WINDOW_get_mem(WINDOW *src, chtype **arrp, int sx, int sy, int len) { int i; int ox, oy; @@ -123,7 +134,7 @@ static int nc_window_get_mem(WINDOW *src, chtype **arrp, int sx, int sy, int len * @sy: starting y coordinate * @len: length of data to copy from @arr (may not exceed its limits) */ -static int nc_window_put_mem(chtype *arr, WINDOW *dst, int sx, int sy, unsigned int len) +static int WINDOW_put_mem(chtype *arr, WINDOW *dst, int sx, int sy, unsigned int len) { int i; int a; @@ -143,7 +154,8 @@ static int nc_window_put_mem(chtype *arr, WINDOW *dst, int sx, int sy, unsigned wattrset(dst, A_NORMAL); /* advancing the cursor position is the good thing about addch() (at least, it is documented behaviour...) */ - for (i = 0; i < len; i++) waddch(dst, arr[i]); + for (i = 0; i < len; i++) + waddch(dst, arr[i]); wattrset(dst, attrs); return 0; } @@ -159,7 +171,7 @@ static int nc_window_put_mem(chtype *arr, WINDOW *dst, int sx, int sy, unsigned * @dx: destination starting x * @dy: destinatino starting y */ -static int nc_window_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int nx, int ny, int dx, int dy) +static int WINDOW_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int nx, int ny, int dx, int dy) { int i, j; chtype *chbuf; /* We ought to have a separate buffer in case @src and @dst overlap */ @@ -181,12 +193,8 @@ static int nc_window_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int n GB.Alloc((void **) &chbuf, nx * ny * sizeof(chtype)); for (i = 0; i < ny; i++) - { for (j = 0; j < nx; j++) - { chbuf[i * nx + j] = mvwinch(src, sy + i, sx + j); - } - } wattrset(dst, A_NORMAL); for (i = 0; i < ny; i++) @@ -194,9 +202,7 @@ static int nc_window_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int n if (dy + i >= getmaxy(dst)) break; wmove(dst, dy + i, dx); for (j = 0; j < nx; j++) - { waddch(dst, chbuf[i * nx + j]); - } } wattrset(dst, dattrs); GB.Free((void **) &chbuf); @@ -207,7 +213,7 @@ static int nc_window_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int n * Unlink and deallocate the main panel together with the window and, if present, the * content window, refresh the screen to immediately remove leftovers of the window. */ -static int nc_window_remove(void *_object) +static int WINDOW_remove(void *_object) { wclear(THIS->content); if (HAS_BORDER) @@ -225,18 +231,19 @@ static int nc_window_remove(void *_object) * Create a content window * The contents of the main window are copied to the newly created content window. */ -static int nc_window_add_content(void *_object) +static int WINDOW_add_content(void *_object) { WINDOW *new; - if (HAS_BORDER) return 0; + if (HAS_BORDER) + return 0; new = derwin(THIS->main, getmaxy(THIS->main) - 2, getmaxx(THIS->main) - 2, 1, 1); keypad(new, TRUE); syncok(new, TRUE); THIS->content = new; /* Copy main window contents, the library only provides overwrite() and friends for this purpose but the windows do not overlap entirely as required by these functions */ - nc_window_main_to_content(); + WINDOW_main_to_content(); /* The main window may not have any additional attributes but the content window */ wattrset(new, getattrs(THIS->main)); wattrset(THIS->main, A_NORMAL); @@ -249,10 +256,11 @@ static int nc_window_add_content(void *_object) * main window pointer. Textual content in the content window and its attributes are copied * to the main window. */ -static int nc_window_remove_content(void *_object) +static int WINDOW_remove_content(void *_object) { - if (!HAS_BORDER) return 0; - nc_window_content_to_main(); + if (!HAS_BORDER) + return 0; + WINDOW_content_to_main(); wattrset(THIS->main, getattrs(THIS->content)); delwin(THIS->content); THIS->content = THIS->main; @@ -264,14 +272,16 @@ static int nc_window_remove_content(void *_object) * @b: 0: erase the border by overwriting it with all spaces * !0: print a border */ -static int nc_window_draw_border(void *_object, bool b) +static int WINDOW_draw_border(void *_object, bool b) { /* TODO: how to check for the possibility of displaying ACS chars? terminfo exports the 'acsc' variable but i couldn't find the format of that string */ - //nc_window_print(THIS, tigetstr("acsc"), -1, -1); - if (b) box(THIS->main, 0, 0); - else wborder(THIS->main, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + //WINDOW_print(THIS, tigetstr("acsc"), -1, -1); + if (b) + box(THIS->main, 0, 0); + else + wborder(THIS->main, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); return 0; } @@ -282,7 +292,7 @@ static int nc_window_draw_border(void *_object, bool b) * Either of the parameters may be -1 which indicates to not change the current * value */ -static int nc_window_cursor_move(void *_object, int x, int y) +static int WINDOW_cursor_move(void *_object, int x, int y) { MAKE_COORDS(THIS->content, x, y); if (BAD_COORDS(THIS->content, x, y)) @@ -305,13 +315,15 @@ static int nc_window_cursor_move(void *_object, int x, int y) * @y: new y coordinate of the upper left corner of the main window relative to the * screen. Again, -1 denotes to leave the value as is */ -static int nc_window_move(void *_object, int x, int y) +static int WINDOW_move(void *_object, int x, int y) { int ox, oy; getbegyx(THIS->main, oy, ox); - if (x == -1) x = ox; - if (y == -1) y = oy; + if (x == -1) + x = ox; + if (y == -1) + y = oy; if (BAD_COORDS(stdscr, x, y)) { GB.Error(E_COORDS); @@ -322,7 +334,7 @@ static int nc_window_move(void *_object, int x, int y) if (HAS_BORDER) { mvwin(THIS->content, y + 1, x + 1); - nc_window_draw_border(THIS, 1); + WINDOW_draw_border(THIS, 1); } return 0; } @@ -336,13 +348,15 @@ static int nc_window_move(void *_object, int x, int y) * The main window is resized accordingly. Values of -1 prevent the present * dimensions from being altered */ -static int nc_window_resize(void *_object, int w, int h) +static int WINDOW_resize(void *_object, int w, int h) { int ow, oh; getmaxyx(THIS->content, ow, oh); - if (w == -1) w = ow; - if (h == -1) h = oh; + if (w == -1) + w = ow; + if (h == -1) + h = oh; if (HAS_BORDER) { @@ -353,7 +367,7 @@ static int nc_window_resize(void *_object, int w, int h) return -1; } - nc_window_draw_border(THIS, 0); + WINDOW_draw_border(THIS, 0); wresize(THIS->main, h + 2, w + 2); } @@ -365,7 +379,8 @@ static int nc_window_resize(void *_object, int w, int h) wresize(THIS->content, h, w) == ERR; replace_panel(THIS->pan, THIS->main); - if (HAS_BORDER) nc_window_draw_border(THIS, 1); + if (HAS_BORDER) + WINDOW_draw_border(THIS, 1); return 0; } @@ -379,7 +394,7 @@ static int nc_window_resize(void *_object, int w, int h) * A set wrapping option causes @str to wrap around to the next line if it doesn't fit. Otherwise * it is truncated at line's end */ -static int nc_window_print(void *_object, char *str, int x, int y) +static int WINDOW_print(void *_object, char *str, int x, int y) { int width, len; char *p; @@ -387,15 +402,19 @@ static int nc_window_print(void *_object, char *str, int x, int y) p = str; do { - if (nc_window_cursor_move(THIS, x, y) == -1) return -1; + if (WINDOW_cursor_move(THIS, x, y) == -1) + return -1; width = getmaxx(THIS->content) - x; - if ((len = strlen(p)) < width) width = len; + if ((len = strlen(p)) < width) + width = len; waddnstr(THIS->content, p, width); p += width; - if (!THIS->wrap) break; + if (!THIS->wrap) + break; x = 0; y++; - if (y >= getmaxy(THIS->content)) break; + if (y >= getmaxy(THIS->content)) + break; } while (*p); return 0; @@ -415,7 +434,7 @@ static int nc_window_print(void *_object, char *str, int x, int y) * it is obvious that if this function leads to stack overflow something was seriously screwed up in the earlier * call contexts (or the terminal has about 2^penguin gazillion lines). */ -int nc_window_insert(void *_object, char *str, int x, int y) +int WINDOW_insert(void *_object, char *str, int x, int y) { static int ex = 0, ey = 0; /* hold the cursor positions where the inserted text will end */ int len, res, a; @@ -427,13 +446,13 @@ int nc_window_insert(void *_object, char *str, int x, int y) it does not preserve the attributes of the formerly present text */ rec++; - if (nc_window_cursor_move(THIS, x, y) == -1) + if (WINDOW_cursor_move(THIS, x, y) == -1) { res = -1; goto _return; } - /* we need the real vals, nc_window_cursor_move() interpreted the -1 values for us */ + /* we need the real vals, WINDOW_cursor_move() interpreted the -1 values for us */ x = getcurx(THIS->content); y = getcury(THIS->content); if (rec == 1) /* first call, initialise all static control data */ @@ -487,14 +506,14 @@ int nc_window_insert(void *_object, char *str, int x, int y) to reset it here (would have been nice to leave that fact in the manpages...) */ mvwinsstr(THIS->content, y, x, str); strcpy(shifted, temp); - nc_window_insert(THIS, shifted, 0, y + 1); + WINDOW_insert(THIS, shifted, 0, y + 1); } res = 0; _return: if (!--rec) { - nc_window_cursor_move(THIS, ex, ey); + WINDOW_cursor_move(THIS, ex, ey); REFRESH(); if (shifted) { @@ -520,12 +539,13 @@ int nc_window_insert(void *_object, char *str, int x, int y) * If wrapping is set for the window, the entire content, which means all lines, are shifted. If wrapping * was turned off, only the current line is shifted but not wrapped around if the end is reached. */ -static int nc_window_insert(void *_object, char *str, int x, int y) +static int WINDOW_insert(void *_object, char *str, int x, int y) { int a, i, len, slen; chtype *ins, *shifted; - if (nc_window_cursor_move(THIS, x, y) == -1) return -1; + if (WINDOW_cursor_move(THIS, x, y) == -1) + return -1; if (!THIS->wrap) { winsstr(THIS->content, str); @@ -538,15 +558,16 @@ static int nc_window_insert(void *_object, char *str, int x, int y) len = strlen(str); slen = getmaxy(THIS->content) * getmaxx(THIS->content) - a - len + 1; GB.Alloc((void **) &ins, len * sizeof(chtype)); - for (i = 0; i < len; i++) ins[i] = (chtype) str[i] | getattrs(THIS->content); - nc_window_get_mem(THIS->content, &shifted, x, y, getmaxy(THIS->content) * getmaxx(THIS->content) - a); + for (i = 0; i < len; i++) + ins[i] = (chtype) str[i] | getattrs(THIS->content); + WINDOW_get_mem(THIS->content, &shifted, x, y, getmaxy(THIS->content) * getmaxx(THIS->content) - a); - nc_window_put_mem(ins, THIS->content, x, y, len); + WINDOW_put_mem(ins, THIS->content, x, y, len); getyx(THIS->content, y, x); - nc_window_put_mem(shifted, THIS->content, x, y, slen); + WINDOW_put_mem(shifted, THIS->content, x, y, slen); /* place the cursor after the last inserted char */ - nc_window_cursor_move(THIS, x, y); + WINDOW_cursor_move(THIS, x, y); GB.Free((void **) &shifted); GB.Free((void **) &ins); @@ -563,17 +584,19 @@ static int nc_window_insert(void *_object, char *str, int x, int y) * @x and @y may be -1. If @len is -1 we shall read until the end of line. * The cursor position is reset after the operation. */ -static int nc_window_get_str(void *_object, int x, int y, unsigned int len, char **ret) +static int WINDOW_get_str(void *_object, int x, int y, unsigned int len, char **ret) { int i; chtype *chbuf; char *buf; - if (len == -1) len = getmaxx(THIS->content) - getcurx(THIS->content); + if (len == -1) + len = getmaxx(THIS->content) - getcurx(THIS->content); GB.Alloc((void **) &buf, len + 1); - nc_window_get_mem(THIS->content, &chbuf, x, y, len); - for (i = 0; i < len; i++) buf[i] = chbuf[i] & A_CHARTEXT; + WINDOW_get_mem(THIS->content, &chbuf, x, y, len); + for (i = 0; i < len; i++) + buf[i] = chbuf[i] & A_CHARTEXT; buf[len] = 0; GB.Free((void **) &chbuf); @@ -587,7 +610,7 @@ static int nc_window_get_str(void *_object, int x, int y, unsigned int len, char * 0 will be delivered back. A negative value denotes to not use any timeout. * @ret: the key value (or 0 in case of timeout expiration) will be stored at this address. */ -static int nc_window_key_timeout(void *_object, int timeout, int *ret) +static int WINDOW_key_timeout(void *_object, int timeout, int *ret) { /* wtimeout() and wgetch() cause ncurses, for whatever reason, to mess up the panel layout: the particular window gets risen to the top of everything. Consequently @@ -598,18 +621,27 @@ static int nc_window_key_timeout(void *_object, int timeout, int *ret) { /* Had a timeout, the manual doesn't define any errors to happen for wgetch() besides NULL pointer arguments. The only source of ERR is timeout expired. */ - if (timeout >= 0) *ret = 0; + if (timeout >= 0) + *ret = 0; } timeout(-1); return 0; } +/** + * Flush the input queue + */ +static void WINDOW_flush() +{ + flushinp(); +} + /** * Move the main panel to the bottom of the panel stack thus arrange it * below all other windows that may overlap it */ -static int nc_window_bottom(void *_object) +static int WINDOW_bottom(void *_object) { bottom_panel(THIS->pan); return 0; @@ -618,7 +650,7 @@ static int nc_window_bottom(void *_object) /** * Move the main panel to the top of the panel stack */ -static int nc_window_top(void *_object) +static int WINDOW_top(void *_object) { top_panel(THIS->pan); return 0; @@ -627,7 +659,7 @@ static int nc_window_top(void *_object) /** * Remove the main panel from the panel stack thus hiding it from the user */ -static int nc_window_hide(void *_object) +static int WINDOW_hide(void *_object) { hide_panel(THIS->pan); return 0; @@ -637,7 +669,7 @@ static int nc_window_hide(void *_object) * Insert the main panel into the panel stack. note that the panel is moved to the top * of the stack thus making it "the most" visible */ -static int nc_window_show(void *_object) +static int WINDOW_show(void *_object) { show_panel(THIS->pan); return 0; @@ -647,13 +679,14 @@ static int nc_window_show(void *_object) * Callback for data on stdin * @fd: stdin means 0 * @type: having watched stdin for read means GB_WATCH_READ + * @param: NULL since we don't need it * This function raises the Read event. Since only one callback appears to be able to * be registered for an fd, there can only be one window to raise this event, i.e. * the one being set to "have the focus" via Window.SetFocus() */ -static void nc_window_read_callback(int fd, int type, void *_object) +static void WINDOW_read_callback(int fd, int type, void *param) { - GB.Raise(THIS, EVENT_Read, 0); + GB.Raise(focused, EVENT_Read, 0); } /** @@ -661,10 +694,14 @@ static void nc_window_read_callback(int fd, int type, void *_object) * Read event if data arrives on stdin. The global variable @focussed is used to * keep track of that very window */ -static int nc_window_setfocus(void *_object) +static int WINDOW_setfocus(void *_object) { - focussed = THIS; - GB.Watch(0, GB_WATCH_READ, nc_window_read_callback, (intptr_t) THIS); + if (!focused) + GB.Watch(0, GB_WATCH_READ, WINDOW_read_callback, 0); + else + GB.Unref((void **) &focused); + focused = THIS; + GB.Ref((void **) &focused); return 0; } @@ -672,11 +709,13 @@ static int nc_window_setfocus(void *_object) * Import a window and fill the @_object with default values (actual object instanciation) * @imp: WINDOW to import */ -static int nc_window_import(void *_object, WINDOW *imp) +static int WINDOW_import(void *_object, WINDOW *imp) { /* Clean up former members */ - if (HAS_BORDER) nc_window_remove_content(THIS); - if (THIS->main) nc_window_remove(THIS); + if (HAS_BORDER) + WINDOW_remove_content(THIS); + if (THIS->main) + WINDOW_remove(THIS); THIS->main = imp; THIS->pan = new_panel(imp); @@ -695,7 +734,7 @@ static int nc_window_import(void *_object, WINDOW *imp) * This routine works with "normal" attributes and colors indifferently (as the latter are * attributes) */ -static int nc_window_attrs_driver(void *_object, int attr, int req) +static int WINDOW_attrs_driver(void *_object, int attr, int req) { switch (req) { @@ -716,10 +755,10 @@ static int nc_window_attrs_driver(void *_object, int attr, int req) * @x: x coordinate * @y: y coordinate * @req: request to perform - * As this is the character-based counterpart to nc_window_attrs_driver, this + * As this is the character-based counterpart to WINDOW_attrs_driver, this * also handles colors */ -static int nc_window_char_attrs_driver(void *_object, int attr, int x, int y, int req) +static int WINDOW_char_attrs_driver(void *_object, int attr, int x, int y, int req) { int ox, oy; int res; @@ -734,7 +773,7 @@ static int nc_window_char_attrs_driver(void *_object, int attr, int x, int y, in for (shift = 0; mask & 1; shift++, mask >>= 1); getyx(THIS->content, oy, ox); - nc_window_cursor_move(THIS, x, y); + WINDOW_cursor_move(THIS, x, y); ch = winch(THIS->content); switch (req) { @@ -752,7 +791,7 @@ static int nc_window_char_attrs_driver(void *_object, int attr, int x, int y, in res = 0; _cleanup: - nc_window_cursor_move(THIS, ox, oy); + WINDOW_cursor_move(THIS, ox, oy); return res; } @@ -760,46 +799,52 @@ static int nc_window_char_attrs_driver(void *_object, int attr, int x, int y, in * Window class */ -BEGIN_PROPERTY(CWindow_windowattrs) +BEGIN_PROPERTY(Window_Attrs) - THIS->pos.line = -1; - THIS->pos.col = -1; RETURN_SELF(); END_PROPERTY -BEGIN_PROPERTY(CWindow_background) +BEGIN_PROPERTY(Window_Background) ; END_PROPERTY -BEGIN_PROPERTY(CWindow_border) +BEGIN_PROPERTY(Window_Border) bool b; int x, y; - if (READ_PROPERTY) GB.ReturnBoolean(THIS->border); + if (READ_PROPERTY) + { + GB.ReturnBoolean(THIS->border); + return; + } + b = VPROP(GB_BOOLEAN); - if (b == THIS->border) return; + if (b == THIS->border) + return; + + /* FIXME: try Full() and then Border = True */ if (b) { - nc_window_resize(THIS, getmaxx(THIS->content) + 2, getmaxy(THIS->content) + 2); - nc_window_move(THIS, (x = getbegx(THIS->main) - 1) == -1 ? 0 : x, + WINDOW_resize(THIS, getmaxx(THIS->content) + 2, getmaxy(THIS->content) + 2); + WINDOW_move(THIS, (x = getbegx(THIS->main) - 1) == -1 ? 0 : x, (y = getbegy(THIS->main) - 1) == -1 ? 0 : y); - nc_window_add_content(THIS); - nc_window_draw_border(THIS, 1); + WINDOW_add_content(THIS); + WINDOW_draw_border(THIS, 1); } else { /* FIXME: routine logic */ /* FIXME: try Border = False if the window is Full() */ - nc_window_draw_border(THIS, 0); - nc_window_remove_content(THIS); - THIS->border = b; /* FIXME: this is important here due to the automatic border-redraw in nc_window_resize */ - nc_window_resize(THIS, getmaxx(THIS->content) - 2, getmaxy(THIS->content) - 2); - nc_window_move(THIS, (x = getbegx(THIS->main) + 1) >= getmaxx(THIS->main) ? getmaxx(THIS->main) - 1 : x, + WINDOW_draw_border(THIS, 0); + WINDOW_remove_content(THIS); + THIS->border = b; /* FIXME: this is important here due to the automatic border-redraw in WINDOW_resize */ + WINDOW_resize(THIS, getmaxx(THIS->content) - 2, getmaxy(THIS->content) - 2); + WINDOW_move(THIS, (x = getbegx(THIS->main) + 1) >= getmaxx(THIS->main) ? getmaxx(THIS->main) - 1 : x, (y = getbegy(THIS->main) + 1) >= getmaxy(THIS->main) ? getmaxy(THIS->main) - 1 : y); } THIS->border = b; @@ -807,61 +852,72 @@ BEGIN_PROPERTY(CWindow_border) END_PROPERTY -BEGIN_PROPERTY(CWindow_container_height) +BEGIN_PROPERTY(Window_Buffered) + + if (READ_PROPERTY) + { + GB.ReturnBoolean(THIS->buffered); + return; + } + THIS->buffered = VPROP(GB_BOOLEAN); + +END_PROPERTY + +BEGIN_PROPERTY(Window_ContainerHeight) GB.ReturnInteger(getmaxy(THIS->main)); END_PROPERTY -BEGIN_PROPERTY(CWindow_container_width) +BEGIN_PROPERTY(Window_ContainerWidth) GB.ReturnInteger(getmaxx(THIS->main)); END_PROPERTY -BEGIN_PROPERTY(CWindow_cursorx) +BEGIN_PROPERTY(Window_CursorX) if (READ_PROPERTY) { GB.ReturnInteger(getcurx(THIS->content)); return; } - nc_window_cursor_move(THIS, VPROP(GB_INTEGER), -1); + WINDOW_cursor_move(THIS, VPROP(GB_INTEGER), -1); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CWindow_cursory) +BEGIN_PROPERTY(Window_CursorY) if (READ_PROPERTY) { GB.ReturnInteger(getcury(THIS->content)); return; } - nc_window_cursor_move(THIS, -1, VPROP(GB_INTEGER)); + WINDOW_cursor_move(THIS, -1, VPROP(GB_INTEGER)); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CWindow_foreground) +BEGIN_PROPERTY(Window_Foreground) ; END_PROPERTY -BEGIN_PROPERTY(CWindow_height) +BEGIN_PROPERTY(Window_Height) if (READ_PROPERTY) { GB.ReturnInteger(getmaxy(THIS->content)); return; } - nc_window_resize(THIS, -1, VPROP(GB_INTEGER)); + WINDOW_resize(THIS, -1, VPROP(GB_INTEGER)); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CWindow_wrap) +BEGIN_PROPERTY(Window_Wrap) /* This property only affects subsequent prints */ if (READ_PROPERTY) @@ -873,51 +929,43 @@ BEGIN_PROPERTY(CWindow_wrap) END_PROPERTY -BEGIN_PROPERTY(CWindow_width) +BEGIN_PROPERTY(Window_Width) if (READ_PROPERTY) { GB.ReturnInteger(getmaxx(THIS->content)); return; } - nc_window_resize(THIS, VPROP(GB_INTEGER), -1); + WINDOW_resize(THIS, VPROP(GB_INTEGER), -1); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CWindow_x) +BEGIN_PROPERTY(Window_X) if (READ_PROPERTY) { GB.ReturnInteger(getbegx(THIS->main)); return; } - nc_window_move(THIS, VPROP(GB_INTEGER), -1); + WINDOW_move(THIS, VPROP(GB_INTEGER), -1); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CWindow_y) +BEGIN_PROPERTY(Window_Y) if (READ_PROPERTY) { GB.ReturnInteger(getbegy(THIS->main)); return; } - nc_window_move(THIS, -1, VPROP(GB_INTEGER)); + WINDOW_move(THIS, -1, VPROP(GB_INTEGER)); REFRESH(); END_PROPERTY -//GB_TIMER *timer; - -//void nc_timer_callback(intptr_t param) -//{ -// addch('A' | A_REVERSE);refresh(); -// GB.Unref(&timer); -//} - -BEGIN_METHOD(CWindow_new, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h) +BEGIN_METHOD(Window_new, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h) WINDOW *new; @@ -927,65 +975,71 @@ BEGIN_METHOD(CWindow_new, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h return; } new = newwin(VARG(h), VARG(w), VARG(y), VARG(x)); - nc_window_import(THIS, new); - -// timer = GB.Every(1000, nc_timer_callback, NULL); -// GB.Ref(&timer); + WINDOW_import(THIS, new); REFRESH(); END_METHOD -BEGIN_METHOD_VOID(CWindow_free) +BEGIN_METHOD_VOID(Window_free) - nc_window_remove(THIS); - if (focussed == THIS) GB.Watch(0, GB_WATCH_NONE, NULL, (intptr_t) NULL); + WINDOW_remove(THIS); + if (focused == THIS) + GB.Watch(0, GB_WATCH_NONE, NULL, 0); + /* the REFRESH() makes use of THIS so it would be unwise to call it + since we just invalidated it */ + REAL_REFRESH(); + +END_METHOD + +BEGIN_METHOD(Window_get, GB_INTEGER y; GB_INTEGER x) + + THIS->pos.line = VARG(y); + THIS->pos.col = VARG(x); + RETURN_SELF(); + +END_METHOD + +BEGIN_METHOD(Window_Ask, GB_STRING opts; GB_INTEGER tries) + + bool miss; + int t, ch; + char *o, c[2]; + + miss = MISSING(tries); + if (!miss) + t = VARG(tries); + else + t = -1; /* just to silence the compiler */ + + o = STRING(opts); + + while (miss || t--) + { + ch = getch(); + /* Per convention, only dealing with byte chars */ + if (ch > 255) + continue; + *c = (char) ch; + if (strchr(o, *c)) + { + c[1] = 0; + GB.ReturnNewZeroString(c); + return; + } + } + GB.ReturnNull(); + +END_METHOD + +BEGIN_METHOD_VOID(Window_Bottom) + + WINDOW_bottom(THIS); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_get, GB_INTEGER y; GB_INTEGER x; GB_INTEGER len) - - int gx, gy, glen; - char *ret; - - gy = VARG(y); - /* if x parameter is missing, we start at the beginning of the line */ - if (MISSING(x)) gx = 0; - else gx = VARG(x); - - /* if no length is given, we return until the end of the line */ - if (MISSING(len)) glen = -1; - else glen = VARG(len); - - nc_window_get_str(THIS, gx, gy, glen, &ret); - GB.ReturnNewZeroString(ret); - GB.Free((void **) &ret); - -END_METHOD - -BEGIN_METHOD(CWindow_put, GB_STRING text; GB_INTEGER y; GB_INTEGER x) - - int sx, sy; - - sy = VARG(y); - - if (MISSING(x)) sx = 0; - else sx = VARG(x); - - nc_window_print(THIS, STRING(text), sx, sy); - REFRESH(); - -END_METHOD - -BEGIN_METHOD_VOID(CWindow_bottom) - - nc_window_bottom(THIS); - REFRESH(); - -END_METHOD - -BEGIN_METHOD_VOID(CWindow_cls) +BEGIN_METHOD_VOID(Window_Cls) /* ncurses sets the cursor to 0,0 after wclear() which may or may not be surprising. */ @@ -994,23 +1048,47 @@ BEGIN_METHOD_VOID(CWindow_cls) END_METHOD -BEGIN_METHOD_VOID(CWindow_full) +BEGIN_METHOD_VOID(Window_Flush) - nc_window_move(THIS, 0, 0); - if (HAS_BORDER) nc_window_resize(THIS, COLS - 2, LINES - 2); - else nc_window_resize(THIS, COLS, LINES); + WINDOW_flush(); + +END_METHOD + +BEGIN_METHOD_VOID(Window_Full) + + WINDOW_move(THIS, 0, 0); + if (HAS_BORDER) + WINDOW_resize(THIS, COLS - 2, LINES - 2); + else + WINDOW_resize(THIS, COLS, LINES); REFRESH(); END_METHOD -BEGIN_METHOD_VOID(CWindow_hide) +BEGIN_METHOD(Window_Get, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len) - nc_window_hide(THIS); + int l; + char *ret; + + /* if no @len is given, we return until the end of the line */ + if (MISSING(len)) + l = -1; + else + l = VARG(len); + WINDOW_get_str(THIS, VARG(x), VARG(y), l, &ret); + GB.ReturnNewZeroString(ret); + GB.Free((void **) &ret); + +END_METHOD + +BEGIN_METHOD_VOID(Window_Hide) + + WINDOW_hide(THIS); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_hline, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRING ch; GB_INTEGER thickness) +BEGIN_METHOD(Window_DrawHLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRING ch; GB_INTEGER thickness) int ox, oy, gx, gy; char c; @@ -1020,78 +1098,123 @@ BEGIN_METHOD(CWindow_hline, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRIN getyx(THIS->content, oy, ox); c = *(STRING(ch)); length = VARG(len); - if (MISSING(thickness)) t = 1; - else t = VARG(thickness); + if (MISSING(thickness)) + t = 1; + else + t = VARG(thickness); gx = VARG(x); gy = VARG(y); for (i = 0; i < t; i++) { - nc_window_cursor_move(THIS, gx, gy); + WINDOW_cursor_move(THIS, gx, gy); whline(THIS->content, c, length); gy++; } - nc_window_cursor_move(THIS, ox, oy); + WINDOW_cursor_move(THIS, ox, oy); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_insert, GB_STRING text; GB_INTEGER x; GB_INTEGER y) +BEGIN_METHOD(Window_Insert, GB_STRING text; GB_INTEGER x; GB_INTEGER y) - nc_window_insert(THIS, STRING(text), MISSING(x) ? -1 : VARG(x), MISSING(y) ? -1 : VARG(y)); + WINDOW_insert(THIS, STRING(text), MISSING(x) ? -1 : VARG(x), MISSING(y) ? -1 : VARG(y)); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_locate, GB_INTEGER x; GB_INTEGER y) +BEGIN_METHOD(Window_Locate, GB_INTEGER x; GB_INTEGER y) - nc_window_cursor_move(THIS, VARG(x), VARG(y)); + WINDOW_cursor_move(THIS, VARG(x), VARG(y)); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_move, GB_INTEGER x; GB_INTEGER y) +BEGIN_METHOD(Window_Move, GB_INTEGER x; GB_INTEGER y) - nc_window_move(THIS, MISSING(x) ? -1 : VARG(x), MISSING(y) ? -1 : VARG(y)); + WINDOW_move(THIS, MISSING(x) ? -1 : VARG(x), MISSING(y) ? -1 : VARG(y)); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_print, GB_STRING text; GB_INTEGER x; GB_INTEGER y) +BEGIN_METHOD(Window_Print, GB_STRING text; GB_INTEGER x; GB_INTEGER y) - nc_window_print(THIS, STRING(text), MISSING(x) ? -1 : VARG(x), MISSING(y) ? -1 : VARG(y)); + WINDOW_print(THIS, STRING(text), MISSING(x) ? -1 : VARG(x), MISSING(y) ? -1 : VARG(y)); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_resize, GB_INTEGER w; GB_INTEGER h) +BEGIN_METHOD(Window_PrintCenter, GB_STRING text) - nc_window_resize(THIS, MISSING(w) ? -1 : VARG(w), MISSING(h) ? -1 : VARG(h)); + int lines = 1; + int x, y; + char *p, *q; + + p = STRING(text); + while ((q = strchr(p, '\n'))) + { + lines++; + p = q + 1; + } + + p = STRING(text); + y = (getmaxy(THIS->content) - lines) / 2; + while (lines--) + { + if (!lines) + { + x = (getmaxx(THIS->content) - strlen(p)) / 2; + WINDOW_print(THIS, p, x, y); + } + else + { + q = strchr(p, '\n'); + *q = 0; + x = (getmaxx(THIS->content) - (q - p)) / 2; + WINDOW_print(THIS, p, x, y); + y++; + p = q + 1; + *q = '\n'; + } + } REFRESH(); END_METHOD -BEGIN_METHOD_VOID(CWindow_show) +BEGIN_METHOD_VOID(Window_Refresh) - nc_window_show(THIS); + REAL_REFRESH(); + +END_METHOD + +BEGIN_METHOD(Window_Resize, GB_INTEGER w; GB_INTEGER h) + + WINDOW_resize(THIS, MISSING(w) ? -1 : VARG(w), MISSING(h) ? -1 : VARG(h)); REFRESH(); END_METHOD -BEGIN_METHOD_VOID(CWindow_setfocus) +BEGIN_METHOD_VOID(Window_Show) - nc_window_setfocus(THIS); - -END_METHOD - -BEGIN_METHOD_VOID(CWindow_top) - - nc_window_top(THIS); + WINDOW_show(THIS); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_vline, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRING ch; GB_INTEGER thickness) +BEGIN_METHOD_VOID(Window_SetFocus) + + WINDOW_setfocus(THIS); + +END_METHOD + +BEGIN_METHOD_VOID(Window_Top) + + WINDOW_top(THIS); + REFRESH(); + +END_METHOD + +BEGIN_METHOD(Window_DrawVLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRING ch; GB_INTEGER thickness) int ox, oy, gx, gy; char c; @@ -1101,31 +1224,35 @@ BEGIN_METHOD(CWindow_vline, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRIN getyx(THIS->content, oy, ox); c = *(STRING(ch)); length = VARG(len); - if (MISSING(thickness)) t = 1; - else t = VARG(thickness); + if (MISSING(thickness)) + t = 1; + else + t = VARG(thickness); gx = VARG(x); gy = VARG(y); for (i = 0; i < t; i++) { - nc_window_cursor_move(THIS, gx, gy); + WINDOW_cursor_move(THIS, gx, gy); wvline(THIS->content, c, length); gx++; } - nc_window_cursor_move(THIS, ox, oy); + WINDOW_cursor_move(THIS, ox, oy); REFRESH(); END_METHOD -BEGIN_METHOD(CWindow_waitkey, GB_INTEGER timeout) +BEGIN_METHOD(Window_WaitKey, GB_INTEGER timeout) int t; int ret; - if (MISSING(timeout)) t = -1; - else t = VARG(timeout); + if (MISSING(timeout)) + t = -1; + else + t = VARG(timeout); - nc_window_key_timeout(THIS, t, &ret); + WINDOW_key_timeout(THIS, t, &ret); GB.ReturnInteger(ret); END_METHOD @@ -1134,90 +1261,84 @@ END_METHOD * .Window.Attrs virtual class */ -BEGIN_PROPERTY(CWindowAttrs_normal) +BEGIN_PROPERTY(WindowAttrs_Normal) /* normal is special because it turns off all other attributes and can't itself been turned off */ - if (READ_PROPERTY) GB.ReturnBoolean(getattrs(THIS->content) == A_NORMAL); - if (VPROP(GB_BOOLEAN)) wattrset(THIS->content, A_NORMAL); + if (READ_PROPERTY) + GB.ReturnBoolean(getattrs(THIS->content) == A_NORMAL); + if (VPROP(GB_BOOLEAN)) + wattrset(THIS->content, A_NORMAL); END_PROPERTY -BEGIN_PROPERTY(CWindowAttrs_underline) +BEGIN_PROPERTY(WindowAttrs_Underline) WIN_ATTR_METHOD_BOOL(A_UNDERLINE); END_PROPERTY -BEGIN_PROPERTY(CWindowAttrs_reverse) +BEGIN_PROPERTY(WindowAttrs_Reverse) WIN_ATTR_METHOD_BOOL(A_REVERSE); END_PROPERTY -BEGIN_PROPERTY(CWindowAttrs_blink) +BEGIN_PROPERTY(WindowAttrs_Blink) WIN_ATTR_METHOD_BOOL(A_BLINK); END_PROPERTY -BEGIN_PROPERTY(CWindowAttrs_bold) +BEGIN_PROPERTY(WindowAttrs_Bold) WIN_ATTR_METHOD_BOOL(A_BOLD); END_PROPERTY -BEGIN_PROPERTY(CWindowAttrs_color) +BEGIN_PROPERTY(WindowAttrs_Color) //inch() attributes have the pair number, but we give the color pair to attron()? //WIN_COLOR_METHOD(); END_PROPERTY -BEGIN_METHOD(CWindowAttrs_get, GB_INTEGER y; GB_INTEGER x) - - THIS->pos.line = VARG(y); - THIS->pos.col = VARG(x); - RETURN_SELF(); - -END_METHOD - /* * .Char.Attrs virtual class */ -BEGIN_PROPERTY(CCharAttrs_normal) +BEGIN_PROPERTY(CharAttrs_Normal) END_PROPERTY -BEGIN_PROPERTY(CCharAttrs_underline) +BEGIN_PROPERTY(CharAttrs_Underline) CHAR_ATTR_METHOD_BOOL(A_UNDERLINE); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CCharAttrs_reverse) +BEGIN_PROPERTY(CharAttrs_Reverse) CHAR_ATTR_METHOD_BOOL(A_REVERSE); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CCharAttrs_blink) +BEGIN_PROPERTY(CharAttrs_Blink) CHAR_ATTR_METHOD_BOOL(A_BLINK); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CCharAttrs_bold) +BEGIN_PROPERTY(CharAttrs_Bold) CHAR_ATTR_METHOD_BOOL(A_BOLD); REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CCharAttrs_color) +BEGIN_PROPERTY(CharAttrs_Color) END_PROPERTY @@ -1233,66 +1354,74 @@ GB_DESC CWindowDesc[] = GB_CONSTANT("NoTimeout", "i", TIMEOUT_NOTIMEOUT), /* Properties */ - GB_PROPERTY_READ("Attributes", ".Window.Attrs", CWindow_windowattrs), + GB_PROPERTY_READ("Attributes", ".Window.Attrs", Window_Attrs), - GB_PROPERTY("Background", "i", CWindow_background), - GB_PROPERTY("Paper", "i", CWindow_background), + GB_PROPERTY("Background", "i", Window_Background), + GB_PROPERTY("Paper", "i", Window_Background), - GB_PROPERTY("Border", "b", CWindow_border), + GB_PROPERTY("Border", "b", Window_Border), - //GB_PROPERTY("Columns", + GB_PROPERTY("Buffered", "b", Window_Buffered), - GB_PROPERTY_READ("ContainerHeight", "i", CWindow_container_height), - GB_PROPERTY_READ("ContainerH", "i", CWindow_container_height), - GB_PROPERTY_READ("ContainerWidth", "i", CWindow_container_width), - GB_PROPERTY_READ("ComtainerW", "i", CWindow_container_width), + GB_PROPERTY_READ("ContainerHeight", "i", Window_ContainerHeight), + GB_PROPERTY_READ("ContainerH", "i", Window_ContainerHeight), + GB_PROPERTY_READ("ContainerWidth", "i", Window_ContainerWidth), + GB_PROPERTY_READ("ComtainerW", "i", Window_ContainerWidth), - GB_PROPERTY("CursorX", "i", CWindow_cursorx), - GB_PROPERTY("CursorY", "i", CWindow_cursory), + GB_PROPERTY("CursorX", "i", Window_CursorX), + GB_PROPERTY("CursorY", "i", Window_CursorY), - GB_PROPERTY("Foreground", "i", CWindow_foreground), - GB_PROPERTY("Pen", "i", CWindow_foreground), + GB_PROPERTY("Foreground", "i", Window_Foreground), + GB_PROPERTY("Pen", "i", Window_Foreground), - GB_PROPERTY("Height", "i", CWindow_height), - GB_PROPERTY("H", "i", CWindow_height), + GB_PROPERTY("Height", "i", Window_Height), + GB_PROPERTY("H", "i", Window_Height), - GB_PROPERTY("Wrap", "b", CWindow_wrap), + GB_PROPERTY("Wrap", "b", Window_Wrap), - GB_PROPERTY("Width", "i", CWindow_width), - GB_PROPERTY("W", "i", CWindow_width), + GB_PROPERTY("Width", "i", Window_Width), + GB_PROPERTY("W", "i", Window_Width), - GB_PROPERTY("X", "i", CWindow_x), - GB_PROPERTY("Y", "i", CWindow_y), + GB_PROPERTY("X", "i", Window_X), + GB_PROPERTY("Y", "i", Window_Y), /* Methods */ - GB_METHOD("_new", NULL, CWindow_new, "(x)i(y)i(w)i(h)i"), - GB_METHOD("_free", NULL, CWindow_free, NULL), - GB_METHOD("_get", "s", CWindow_get, "(y)i[(x)i(len)i]"), - GB_METHOD("_put", NULL, CWindow_put, "(text)s(y)i[(x)i]"), + GB_METHOD("_new", NULL, Window_new, "(X)i(Y)i(W)i(H)i"), + GB_METHOD("_free", NULL, Window_free, NULL), + GB_METHOD("_get", ".Char.Attrs", Window_get, "(Y)i(X)i"), - GB_METHOD("Bottom", NULL, CWindow_bottom, NULL), - GB_METHOD("Top", NULL, CWindow_top, NULL), + GB_METHOD("Ask", "s", Window_Ask, "(Opts)s[(Tries)i]"), - GB_METHOD("Cls", NULL, CWindow_cls, NULL), + GB_METHOD("Bottom", NULL, Window_Bottom, NULL), + GB_METHOD("Top", NULL, Window_Top, NULL), - GB_METHOD("Full", NULL, CWindow_full, NULL), + GB_METHOD("Cls", NULL, Window_Cls, NULL), - GB_METHOD("Hide", NULL, CWindow_hide, NULL), - GB_METHOD("Show", NULL, CWindow_show, NULL), + GB_METHOD("Flush", NULL, Window_Flush, NULL), - GB_METHOD("HLine", NULL, CWindow_hline, "(x)i(y)i(len)i(ch)s[(thickness)i]"), - GB_METHOD("VLine", NULL, CWindow_vline, "(x)i(y)i(len)i(ch)s[(thickness)i]"), + GB_METHOD("Full", NULL, Window_Full, NULL), - GB_METHOD("Insert", NULL, CWindow_insert, "(text)s[(x)i(y)i]"), - GB_METHOD("Print", NULL, CWindow_print, "(text)s[(x)i(y)i]"), + GB_METHOD("Get", "s", Window_Get, "(X)i(Y)i[(Len)i]"), - GB_METHOD("Locate", NULL, CWindow_locate, "(x)i(y)i"), - GB_METHOD("Move", NULL, CWindow_move, "[(x)i(y)i]"), - GB_METHOD("Resize", NULL, CWindow_resize, "[(w)i(h)i]"), + GB_METHOD("Hide", NULL, Window_Hide, NULL), + GB_METHOD("Show", NULL, Window_Show, NULL), - GB_METHOD("SetFocus", NULL, CWindow_setfocus, NULL), + GB_METHOD("DrawHLine", NULL, Window_DrawHLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"), + GB_METHOD("DrawVLine", NULL, Window_DrawVLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"), - GB_METHOD("WaitKey", "i", CWindow_waitkey, "[(timeout)i]"), + GB_METHOD("Insert", NULL, Window_Insert, "(Text)s[(X)i(Y)i]"), + GB_METHOD("Print", NULL, Window_Print, "(Text)s[(X)i(Y)i]"), + GB_METHOD("PrintCenter", NULL, Window_PrintCenter, "(Text)s"), + + GB_METHOD("Locate", NULL, Window_Locate, "(X)i(Y)i"), + GB_METHOD("Move", NULL, Window_Move, "[(X)i(Y)i]"), + GB_METHOD("Resize", NULL, Window_Resize, "[(W)i(H)i]"), + + GB_METHOD("Refresh", NULL, Window_Refresh, NULL), + + GB_METHOD("SetFocus", NULL, Window_SetFocus, NULL), + + GB_METHOD("WaitKey", "i", Window_WaitKey, "[(Timeout)i]"), GB_END_DECLARE }; @@ -1302,13 +1431,11 @@ GB_DESC CWindowAttrsDesc[] = GB_DECLARE(".Window.Attrs", 0), GB_VIRTUAL_CLASS(), - GB_PROPERTY("Normal", "b", CWindowAttrs_normal), - GB_PROPERTY("Underline", "b", CWindowAttrs_underline), - GB_PROPERTY("Reverse", "b", CWindowAttrs_reverse), - GB_PROPERTY("Blink", "b", CWindowAttrs_blink), - GB_PROPERTY("Bold", "b", CWindowAttrs_bold), - - GB_METHOD("_get", ".Char.Attrs", CWindowAttrs_get, "(y)i(x)i"), + GB_PROPERTY("Normal", "b", WindowAttrs_Normal), + GB_PROPERTY("Underline", "b", WindowAttrs_Underline), + GB_PROPERTY("Reverse", "b", WindowAttrs_Reverse), + GB_PROPERTY("Blink", "b", WindowAttrs_Blink), + GB_PROPERTY("Bold", "b", WindowAttrs_Bold), GB_END_DECLARE }; @@ -1318,13 +1445,13 @@ GB_DESC CCharAttrsDesc[] = GB_DECLARE(".Char.Attrs", 0), GB_VIRTUAL_CLASS(), - GB_PROPERTY("Normal", "b", CCharAttrs_normal), - GB_PROPERTY("Underline", "b", CCharAttrs_underline), - GB_PROPERTY("Reverse", "b", CCharAttrs_reverse), - GB_PROPERTY("Blink", "b", CCharAttrs_blink), - GB_PROPERTY("Bold", "b", CCharAttrs_bold), + GB_PROPERTY("Normal", "b", CharAttrs_Normal), + GB_PROPERTY("Underline", "b", CharAttrs_Underline), + GB_PROPERTY("Reverse", "b", CharAttrs_Reverse), + GB_PROPERTY("Blink", "b", CharAttrs_Blink), + GB_PROPERTY("Bold", "b", CharAttrs_Bold), - GB_PROPERTY("Color", "i", CCharAttrs_color), + //GB_PROPERTY("Color", "i", CCharAttrs_color), GB_END_DECLARE }; diff --git a/gb.ncurses/src/c_window.h b/gb.ncurses/src/c_window.h index fd28783b9..6d510178c 100644 --- a/gb.ncurses/src/c_window.h +++ b/gb.ncurses/src/c_window.h @@ -33,9 +33,13 @@ #define THIS ((struct nc_window *) _object) #define HAS_BORDER (THIS->border) #define IS_WRAPPED (THIS->wrap) -/* This will produce final output on terminal screen, shall be called only by Gambas functions - as they assemble all changes for a single functionality and may then output once. */ -#define REFRESH() WINDOW_refresh() +#define IS_BUFFERED (THIS->buffered) +/* This will produce final output on terminal screen */ +#define REAL_REFRESH() WINDOW_real_refresh() +/* This macro is mostly called by Gambas implementation functions to request output on screen + (read: to check if the output is buffered and if not produce output by means of + REAL_REFRESH(). To check buffering, this need to get an object parameter.) */ +#define REFRESH() WINDOW_refresh(THIS) /* Translate linear (absolute) memory addresses and x,y coordinates into each other most useful when wrapping is needed. */ @@ -48,8 +52,10 @@ } /* Interpret the -1 values in coordinates as to insert the current cursor position */ #define MAKE_COORDS(win, x, y) { \ - if ((x) == -1) x = getcurx(win); \ - if ((y) == -1) y = getcury(win); \ + if ((x) == -1) \ + x = getcurx(win); \ + if ((y) == -1) \ + y = getcury(win); \ } /* Check for out-of-range coordinates */ #define BAD_COORDS(win, x, y) ((x) < 0 || (x) >= getmaxx(win) || \ @@ -70,11 +76,12 @@ enum #define WIN_ATTR_METHOD(b, a) { \ if (READ_PROPERTY) \ - GB.ReturnBoolean(nc_window_attrs_driver( \ + GB.ReturnBoolean(WINDOW_attrs_driver( \ THIS, (a), ATTR_DRV_RET) \ & (a)); \ - else nc_window_attrs_driver( \ - THIS, (a), (b) ? ATTR_DRV_ON : ATTR_DRV_OFF); \ + else \ + WINDOW_attrs_driver(THIS, (a), \ + (b) ? ATTR_DRV_ON : ATTR_DRV_OFF); \ } #define WIN_ATTR_METHOD_BOOL(a) WIN_ATTR_METHOD(VPROP(GB_BOOLEAN), a); #define WIN_ATTR_METHOD_INT(a) WIN_ATTR_METHOD(1, a); @@ -84,12 +91,12 @@ enum line manually. A higher-callstack function may call REFRESH() to get output. */ #define CHAR_ATTR_METHOD(b, a) { \ if (READ_PROPERTY) \ - GB.ReturnBoolean(nc_window_char_attrs_driver( \ + GB.ReturnBoolean(WINDOW_char_attrs_driver( \ THIS, (a), THIS->pos.col, THIS->pos.line, \ ATTR_DRV_RET) & (a)); \ - else nc_window_char_attrs_driver( \ - THIS, (a), THIS->pos.col, THIS->pos.line, \ - (b) ? ATTR_DRV_ON : ATTR_DRV_OFF); \ + else \ + WINDOW_char_attrs_driver(THIS, (a), THIS->pos.col, \ + THIS->pos.line, (b) ? ATTR_DRV_ON : ATTR_DRV_OFF); \ wtouchln(THIS->main, THIS->pos.line + (HAS_BORDER ? 1 : 0), 1, 1); \ } #define CHAR_ATTR_METHOD_BOOL(a) CHAR_ATTR_METHOD(VPROP(GB_BOOLEAN), a); @@ -113,6 +120,8 @@ struct nc_window PANEL *pan; /* Panel of the main window to provide overlapping windows */ bool border; /* Whether there is a border */ bool wrap; /* Whether text shall be truncated or wrapped on line ends */ + bool buffered; /* Whether the output via REFRESH() macro shall be buffered (only a call to + Window.Refresh() will then produce any output) */ struct /* This structure is used to pass a line and a column number to virtual objects */ { int line; @@ -126,13 +135,13 @@ extern GB_DESC CWindowAttrsDesc[]; extern GB_DESC CCharAttrsDesc[]; #endif -#define nc_window_main_to_content() (nc_window_copy_window(THIS->main, THIS->content, 0, 0, \ +#define WINDOW_main_to_content() WINDOW_copy_window(THIS->main, THIS->content, 0, 0, \ getmaxx(THIS->content), \ - getmaxy(THIS->content), 0, 0)) -#define nc_window_content_to_main() (nc_window_copy_window(THIS->content, THIS->main, 0, 0, \ + getmaxy(THIS->content), 0, 0) +#define WINDOW_content_to_main() WINDOW_copy_window(THIS->content, THIS->main, 0, 0, \ getmaxx(THIS->content), \ - getmaxy(THIS->content), 0, 0)) + getmaxy(THIS->content), 0, 0) -void WINDOW_refresh(void); +void WINDOW_real_refresh(); #endif /* __C_WINDOW_C */ diff --git a/gb.ncurses/src/main.c b/gb.ncurses/src/main.c index e45f44d57..42bf8c02f 100644 --- a/gb.ncurses/src/main.c +++ b/gb.ncurses/src/main.c @@ -23,6 +23,7 @@ #include "c_ncurses.h" #include "c_window.h" +#include "c_key.h" #include "main.h" GB_INTERFACE GB EXPORT; @@ -32,7 +33,8 @@ GB_DESC *GB_CLASSES[] EXPORT = CNCursesDesc, CWindowDesc, CWindowAttrsDesc, -// CCharAttrsDesc, + CCharAttrsDesc, + CKeyDesc, NULL }; @@ -41,11 +43,15 @@ static void hook_error(int code, char *error, char *where) NCURSES_exit(); } +static void hook_init() +{ + NCURSES_init(); +} int EXPORT GB_INIT() { - GB.Hook(GB_HOOK_ERROR, (void *)hook_error); - + GB.Hook(GB_HOOK_ERROR, (void *) hook_error); + GB.Hook(GB_HOOK_MAIN, (void *) hook_init); return 0; }