[GB.NCURSES]

* NEW: Window class now inherits Stream
* NEW: Renamed Window.Flush() to Window.Drain() to not have it confused
  with the stream Flush instruction
* NEW: Window.Background and .Foreground properties now work
* NEW: Window.Attributes.Color changed internal behaviour to interoperate
  with .Background and .Foreground properties
* NEW: Now using ncurses extensions to colour support
* BUG: Corrected typo in ContainerW property name



git-svn-id: svn://localhost/gambas/trunk@4700 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
Tobias Boege 2012-04-30 20:31:35 +00:00
parent d76e97be7d
commit 492de27fda
6 changed files with 320 additions and 281 deletions

View File

@ -31,18 +31,67 @@
static int _index;
static int _color;
/**
* Colour initialisation
*/
void COLOR_init()
{
/* TODO: use_default_colors() and assume_default_colors() for more control */
start_color();
use_default_colors();
}
static int COLOR_setpair(short index, short fg, short bg)
/**
* Initialise a colour pair
* @index: colour pair index
* @fg: foreground value
* @bg: background value
*/
int COLOR_setpair(short index, short fg, short bg)
{
init_pair(index, fg, bg);
/* FIXME: on my setup, giving -1 doesn't work after
use_default_colors(). It gives no error but does nothing. I
workaround this issue by assuming COLOR_BLACK and COLOR_WHITE as
defaults for back- and foreground respectively */
if (fg == -1)
fg = COLOR_WHITE;
if (bg == -1)
bg = COLOR_BLACK;
if (index)
init_pair(index, fg, bg);
else
assume_default_colors(fg, bg);
return 0;
}
/**
* Set either foreground or background of a colour pair
* @index: colour pair
* @val: colour
* @what: SETPAIR_* constant to indicate what should be set
*/
int COLOR_setpair_one(short index, short val, int what)
{
short f, b;
pair_content(index, &f, &b);
switch (what) {
case SETPAIR_FORE:
return COLOR_setpair(index, val, b);
case SETPAIR_BACK:
return COLOR_setpair(index, f, val);
}
return -1;
}
/**
* Return the RGB contents of a colour
* @color: colour value to examine
* @r: pointer to variable to be containing red portion
* @g: green
* @b: blue
* The @r, @g, @b values may be NULL in which case the value is discarded
*/
static int COLOR_content(short color, short *r, short *g, short *b)
{
short ar, ag, ab;
@ -75,8 +124,7 @@ END_PROPERTY
BEGIN_METHOD(Color_get, GB_INTEGER index)
if (!PAIR_VALID(VARG(index)))
{
if (!PAIR_VALID(VARG(index))) {
GB.Error(GB_ERR_BOUND);
return;
}
@ -87,8 +135,7 @@ END_METHOD
BEGIN_METHOD(Color_Define, GB_INTEGER color; GB_INTEGER r; GB_INTEGER g; GB_INTEGER b)
if (!COLOR_VALID(VARG(color)))
{
if (!COLOR_VALID(VARG(color))) {
GB.Error(GB_ERR_BOUND);
return;
}
@ -98,8 +145,7 @@ END_METHOD
BEGIN_METHOD(Color_Content, GB_INTEGER color)
if (!COLOR_VALID(VARG(color)))
{
if (!COLOR_VALID(VARG(color))) {
GB.Error(GB_ERR_BOUND);
return;
}
@ -133,13 +179,11 @@ BEGIN_PROPERTY(ColorPair_Background)
short f, b;
pair_content(_index, &f, &b);
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(b);
return;
}
if (!COLOR_VALID(VPROP(GB_INTEGER)))
{
if (!COLOR_VALID(VPROP(GB_INTEGER))) {
GB.Error(GB_ERR_BOUND);
return;
}
@ -154,13 +198,11 @@ BEGIN_PROPERTY(ColorPair_Foreground)
short f, b;
pair_content(_index, &f, &b);
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(f);
return;
}
if (!COLOR_VALID(VPROP(GB_INTEGER)))
{
if (!COLOR_VALID(VPROP(GB_INTEGER))) {
GB.Error(GB_ERR_BOUND);
return;
}

View File

@ -3,8 +3,8 @@
#include <ncurses.h>
#define PAIR_VALID(p) (p > 0 && p < COLOR_PAIRS)
#define COLOR_VALID(c) (c >= 0 && c < COLORS)
#define PAIR_VALID(p) (p >= 0 && p < COLOR_PAIRS)
#define COLOR_VALID(c) (c >= -1 && c < COLORS)
#ifndef __C_COLOR_C
extern GB_DESC CColorDesc[];
@ -13,6 +13,13 @@ extern GB_DESC CColorPairDesc[];
extern GB_DESC CColorContentDesc[];
#endif
enum {
SETPAIR_FORE,
SETPAIR_BACK
};
void COLOR_init();
int COLOR_setpair(short index, short fg, short bg);
int COLOR_setpair_one(short index, short val, int what);
#endif /* __C_COLOR_H */

View File

@ -60,8 +60,7 @@ void NCURSES_init(void)
void NCURSES_exit()
{
if (_init)
{
if (_init) {
endwin();
_init = FALSE;
}

View File

@ -39,6 +39,7 @@
#define INPUT_COOKED 0
#define INPUT_CBREAK 1
#define INPUT_RAW 2
#define INPUT_KEYBOARD 3
static bool _cursor;
static int _input;
@ -63,6 +64,9 @@ void nc_sigwinch_handler(int signum)
}
#endif
/**
* Screen initialisation
*/
int SCREEN_init()
{
/* Global variable default setup */
@ -91,14 +95,12 @@ int SCREEN_init()
BEGIN_PROPERTY(Screen_Cursor)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(_cursor);
return;
}
switch (VPROP(GB_INTEGER))
{
switch (VPROP(GB_INTEGER)) {
case CURSOR_HIDDEN:
curs_set(0);
break;
@ -115,14 +117,12 @@ END_PROPERTY
BEGIN_PROPERTY(Screen_Input)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(_input);
return;
}
switch (VPROP(GB_INTEGER))
{
switch (VPROP(GB_INTEGER)) {
case INPUT_COOKED:
noraw();
nocbreak();
@ -133,6 +133,9 @@ BEGIN_PROPERTY(Screen_Input)
case INPUT_RAW:
raw();
break;
case INPUT_KEYBOARD:
/* TODO: implement! */
break;
default:
GB.Error(E_UNSUPP);
return;
@ -143,15 +146,16 @@ END_PROPERTY
BEGIN_PROPERTY(Screen_Echo)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnBoolean(_echo);
return;
}
_echo = VPROP(GB_BOOLEAN);
if (_echo) echo();
else noecho();
if (_echo)
echo();
else
noecho();
END_PROPERTY

View File

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <ncurses.h>
#include <panel.h>
@ -34,11 +35,37 @@
#include "c_window.h"
#include "c_color.h"
static int Window_stream_open(GB_STREAM *stream, const char *path, int mode, void *data);
static int Window_stream_close(GB_STREAM *stream);
static int Window_stream_read(GB_STREAM *stream, char *buffer, int len);
static int Window_stream_getchar(GB_STREAM *stream, char *buffer);
static int Window_stream_write(GB_STREAM *stream, char *buffer, int len);
static int Window_stream_seek(GB_STREAM *stream, int64_t pos, int whence);
static int Window_stream_tell(GB_STREAM *stream, int64_t *pos);
static int Window_stream_flush(GB_STREAM *stream);
static int Window_stream_eof(GB_STREAM *stream);
static int Window_stream_lof(GB_STREAM *stream, int64_t *len);
static int Window_stream_handle(GB_STREAM *stream);
/* The nc_window currently having the focus (raising Read events) */
static struct nc_window *focused = NULL;
DECLARE_EVENT(EVENT_Read);
GB_STREAM_DESC WindowStream = {
open: Window_stream_open,
close: Window_stream_close,
read: Window_stream_read,
getchar: Window_stream_getchar,
write: Window_stream_write,
seek: Window_stream_seek,
tell: Window_stream_tell,
flush: Window_stream_flush,
eof: Window_stream_eof,
lof: Window_stream_lof,
handle: Window_stream_handle
};
/*
* C Window interface
* @_object: Reference to the struct nc_window representing the current object.
@ -103,20 +130,17 @@ static int WINDOW_get_mem(WINDOW *src, chtype **arrp, int sx, int sy, int len)
getyx(src, oy, ox);
MAKE_COORDS(src, sx, sy);
if (BAD_COORDS(src, sx, sy))
{
if (BAD_COORDS(src, sx, sy)) {
GB.Error(E_COORDS);
return -1;
}
len = MinMax(len, 0, (getmaxy(src) - sy) * getmaxx(src) - sx);
GB.Alloc((void **) arrp, len * sizeof(chtype));
for (i = 0; i < len; i++)
{
for (i = 0; i < len; i++) {
ch = mvwinch(src, sy, sx);
(*arrp)[i] = ch;
if (++sx >= getmaxx(src))
{
if (++sx >= getmaxx(src)) {
sy++;
sx = 0;
}
@ -142,8 +166,7 @@ static int WINDOW_put_mem(chtype *arr, WINDOW *dst, int sx, int sy, unsigned int
int attrs = getattrs(dst);
MAKE_COORDS(dst, sx, sy);
if (BAD_COORDS(dst, sx, sy))
{
if (BAD_COORDS(dst, sx, sy)) {
GB.Error(E_COORDS);
return -1;
}
@ -181,14 +204,12 @@ static int WINDOW_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int nx,
MAKE_COORDS(src, sx, sy);
MAKE_COORDS(dst, dx, dy);
if (BAD_COORDS(src, sx, sy) || BAD_COORDS(dst, dx, dy))
{
if (BAD_COORDS(src, sx, sy) || BAD_COORDS(dst, dx, dy)) {
GB.Error(E_COORDS);
return -1;
}
if (BAD_COORDS(src, sx + nx - 1, sy + ny - 1) ||
BAD_COORDS(dst, dx + nx - 1, dy + ny - 1))
{
BAD_COORDS(dst, dx + nx - 1, dy + ny - 1)) {
GB.Error(E_COORDS);
return -1;
}
@ -202,8 +223,7 @@ static int WINDOW_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int nx,
getyx(dst, oy, ox);
wattrset(dst, A_NORMAL);
for (i = 0; i < ny; i++)
{
for (i = 0; i < ny; i++) {
if (dy + i >= getmaxy(dst)) break;
wmove(dst, dy + i, dx);
for (j = 0; j < nx; j++)
@ -222,8 +242,7 @@ static int WINDOW_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int nx,
static int WINDOW_remove(void *_object)
{
wclear(THIS->content);
if (HAS_BORDER)
{
if (HAS_BORDER) {
delwin(THIS->content);
wclear(THIS->main);
}
@ -283,15 +302,12 @@ static int WINDOW_draw_border(void *_object, bool b)
/* TODO: how to check for the possibility of displaying ACS chars?
Terminfo exports the 'eacs' variable. Anyone to tell whether I understood the bare
information correctly? */
if (b)
{
if (b) {
if (tigetstr("enacs"))
box(THIS->main, 0, 0);
else
wborder(THIS->main, '|', '|', '-', '-', '+', '+', '+', '+');
}
else
{
} else {
wborder(THIS->main, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
}
return 0;
@ -307,14 +323,12 @@ static int WINDOW_draw_border(void *_object, bool b)
static int WINDOW_cursor_move(void *_object, int x, int y)
{
MAKE_COORDS(THIS->content, x, y);
if (BAD_COORDS(THIS->content, x, y))
{
if (BAD_COORDS(THIS->content, x, y)) {
GB.Error(E_COORDS);
return -1;
}
if (wmove(THIS->content, y, x) == ERR)
{
if (wmove(THIS->content, y, x) == ERR) {
GB.Error("Could not move cursor");
return -1;
}
@ -336,15 +350,13 @@ static int WINDOW_move(void *_object, int x, int y)
x = ox;
if (y == -1)
y = oy;
if (BAD_COORDS(stdscr, x, y))
{
if (BAD_COORDS(stdscr, x, y)) {
GB.Error(E_COORDS);
return -1;
}
move_panel(THIS->pan, y, x);
if (HAS_BORDER)
{
if (HAS_BORDER) {
mvwin(THIS->content, y + 1, x + 1);
WINDOW_draw_border(THIS, 1);
}
@ -370,11 +382,9 @@ static int WINDOW_resize(void *_object, int w, int h)
if (h == -1)
h = oh;
if (HAS_BORDER)
{
if (HAS_BORDER) {
if ((w + 2) <= 0 || (w + 2) > COLS ||
(h + 2) <= 0 || (h + 2) > LINES)
{
(h + 2) <= 0 || (h + 2) > LINES) {
GB.Error(E_DIMENSION);
return -1;
}
@ -383,8 +393,7 @@ static int WINDOW_resize(void *_object, int w, int h)
wresize(THIS->main, h + 2, w + 2);
}
if (w <= 0 || w > COLS || h <= 0 || h > LINES)
{
if (w <= 0 || w > COLS || h <= 0 || h > LINES) {
GB.Error(E_DIMENSION);
return -1;
}
@ -412,8 +421,7 @@ static int WINDOW_print(void *_object, char *str, int x, int y)
char *p, *q;
p = str;
do
{
do {
if (WINDOW_cursor_move(THIS, x, y) == -1)
return -1;
width = getmaxx(THIS->content) - x;
@ -430,121 +438,10 @@ static int WINDOW_print(void *_object, char *str, int x, int y)
y++;
if (y >= getmaxy(THIS->content))
break;
}
while (*p);
} while (*p);
return 0;
}
#if 0 /* Works but a simpler, although more memory intense, solution is ready */
/**
* Insert a given string before the cursor position denoted by x,y coordinates shifting what follows
* this position.
* @str: string to insert
* @x: x coordinate
* @y: y coordinate
* -1 as coordinate value means to leave the current value set.
* 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.
* Note that this function calls itself recursively. Regarding the memory usage and recursion end conditions,
* 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 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;
static char *shifted = NULL; /* we have one buffer that is overwritten by each call */
static char *temp = NULL; /* temporary storage to be stored in @shifted */
static int rec = 0; /* keeps track of recursion depth to do optimisation */
/* FIXME: this algorithm really messes up the view when wrapped and e.g. A_REVERSE is set on the window:
it does not preserve the attributes of the formerly present text */
rec++;
if (WINDOW_cursor_move(THIS, x, y) == -1)
{
res = -1;
goto _return;
}
/* 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 */
{
XY2A(THIS->content, getmaxx(THIS->content) - 1, getmaxy(THIS->content) - 1, a);
a += strlen(str);
A2XY(THIS->content, a, ex, ey);
/* the text may fill the entire box, so we better catch that and locate the cursor
at the end in that case */
if (ey >= getmaxy(THIS->content))
{
ex = getmaxx(THIS->content) - 1;
ey = getmaxy(THIS->content) - 1;
}
}
/* if we're on the last line, nothing will be wrapped around at all, so we take this branch.
in this case, the call works exactly like the non-wrapping insert and begins to unroll the
recursion. */
if (!THIS->wrap || y == getmaxy(THIS->content) - 1)
{
mvwinsstr(THIS->content, y, x, str);
}
else
{
len = strlen(str);
if (rec == 1)
{
if (!(shifted = malloc(len + 1)) || !(temp = malloc(len + 1)))
{
GB.Error("Could not allocate memory");
res = -1;
goto _return;
}
}
/* if the @str itself overflows the line, there will be a remainder of
it that has to preceed the shifted string to be wrapped to the next line */
if (x + len > getmaxx(THIS->content))
{
len = getmaxx(THIS->content) - x;
strcpy(temp, str + len);
winstr(THIS->content, temp + strlen(temp));
}
else
{
/* remainder on the right (giving a negative @n to winnstr() family seems broken
in my library and may be elsewhere (manpages say it's an extension to XSI curses) */
mvwinstr(THIS->content, y, getmaxx(THIS->content) - len, temp);
}
/* the winnstr() family of functions used to extract shifted characters moves the cursor, we have
to reset it here (would have been nice to leave that fact in the manpages...) */
mvwinsstr(THIS->content, y, x, str);
strcpy(shifted, temp);
WINDOW_insert(THIS, shifted, 0, y + 1);
}
res = 0;
_return:
if (!--rec)
{
WINDOW_cursor_move(THIS, ex, ey);
REFRESH();
if (shifted)
{
free(shifted);
shifted = NULL;
}
if (temp)
{
free(temp);
temp = NULL;
}
}
return res;
}
#endif
/**
* Insert a given string before the cursor position denoted by x,y and shift what follows it
* @str: string to insert
@ -561,8 +458,7 @@ static int WINDOW_insert(void *_object, char *str, int x, int y)
if (WINDOW_cursor_move(THIS, x, y) == -1)
return -1;
if (!THIS->wrap)
{
if (!THIS->wrap) {
winsstr(THIS->content, str);
return 0;
}
@ -630,24 +526,25 @@ 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
I use the stdscr here which appears to not suffer from this. */
timeout(timeout);
if (timeout >= 0)
timeout(timeout);
*ret = getch();
if (*ret == ERR)
{
if (*ret == ERR) {
/* 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;
}
timeout(-1);
if (timeout >= 0)
timeout(-1);
return 0;
}
/**
* Flush the input queue
* Drain the input queue
*/
static void WINDOW_flush()
static void WINDOW_drain()
{
flushinp();
}
@ -751,16 +648,17 @@ static int WINDOW_import(void *_object, WINDOW *imp)
*/
static int WINDOW_attrs_driver(void *_object, int attr, int req)
{
switch (req)
{
switch (req) {
case ATTR_DRV_RET:
return getattrs(THIS->content);
case ATTR_DRV_COL:
case ATTR_DRV_ON:
wattron(THIS->content, attr);
break;
case ATTR_DRV_OFF:
wattroff(THIS->content, attr);
break;
case ATTR_DRV_COL:
wbkgd(THIS->content, attr | ' ');
}
return 0;
}
@ -786,8 +684,7 @@ static int WINDOW_char_attrs_driver(void *_object, int attr, int x, int y, int r
getyx(THIS->content, oy, ox);
WINDOW_cursor_move(THIS, x, y);
ch = winch(THIS->content);
switch (req)
{
switch (req) {
case ATTR_DRV_RET:
res = ch & A_ATTRIBUTES;
goto _cleanup;
@ -807,19 +704,115 @@ static int WINDOW_char_attrs_driver(void *_object, int attr, int x, int y, int r
return res;
}
/*
* Window stream functions
*/
static int Window_stream_open(GB_STREAM *stream, const char *path, int mode, void *data)
{
return -1;
}
static int Window_stream_close(GB_STREAM *stream)
{
return -1;
}
static int Window_stream_read(GB_STREAM *stream, char *buffer, int len)
{
STREAM_PROLOGUE();
int key, res;
/* We only support reading Byte or Integer. */
switch (len) {
case sizeof(char):
return Window_stream_getchar(stream, buffer);
case sizeof(int):
res = WINDOW_key_timeout(THIS, -1, &key);
*((int *) buffer) = key;
return res;
default:
return -1;
}
}
static int Window_stream_getchar(GB_STREAM *stream, char *buffer)
{
STREAM_PROLOGUE();
int key, res;
res = WINDOW_key_timeout(THIS, -1, &key);
*buffer = (char) key;
return res;
}
static int Window_stream_write(GB_STREAM *stream, char *buffer, int len)
{
STREAM_PROLOGUE();
/* However, we terminate at the first NUL byte */
return WINDOW_print(THIS, buffer, -1, -1);
}
static int Window_stream_seek(GB_STREAM *steram, int64_t pos, int whence)
{
return -1;
}
static int Window_stream_tell(GB_STREAM *stream, int64_t *pos)
{
return -1;
}
static int Window_stream_flush(GB_STREAM *stream)
{
REAL_REFRESH();
return 0;
}
static int Window_stream_eof(GB_STREAM *stream)
{
int n;
/* Safest method */
if (ioctl(0, TIOCINQ, &n) == -1)
return -1;
return n ? 1 : 0;
}
static int Window_stream_lof(GB_STREAM *stream, int64_t *len)
{
return ioctl(0, TIOCINQ, len);
}
static int Window_stream_handle(GB_STREAM *stream)
{
/* There's no clear 'handle', we operate on stdin or stdout depending on context */
return -1;
}
/*
* Window class
*/
BEGIN_PROPERTY(Window_Attrs)
RETURN_SELF();
END_PROPERTY
BEGIN_PROPERTY(Window_Background)
;
short pair;
short f, b;
pair = PAIR_NUMBER(getbkgd(THIS->content));
pair_content(pair, &f, &b);
if (READ_PROPERTY) {
GB.ReturnInteger(b);
return;
}
b = VPROP(GB_INTEGER);
if (!COLOR_VALID(b)) {
GB.Error(GB_ERR_BOUND);
return;
}
COLOR_setpair(pair, f, b);
wbkgd(THIS->content, COLOR_PAIR(pair) | ' ');
END_PROPERTY
@ -828,8 +821,7 @@ BEGIN_PROPERTY(Window_Border)
bool b;
int x, y, w, h;
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnBoolean(THIS->border);
return;
}
@ -839,17 +831,14 @@ BEGIN_PROPERTY(Window_Border)
if (b == THIS->border)
return;
if (b)
{
if (b) {
WINDOW_resize(THIS, (w = getmaxx(THIS->main) + 2) > COLS ? getmaxx(THIS->main) : w,
(h = getmaxy(THIS->main) + 2) > LINES ? getmaxy(THIS->main) : h);
WINDOW_move(THIS, (x = getbegx(THIS->main) - 1) < 0 ? 0 : x,
(y = getbegy(THIS->main) - 1) < 0 ? 0 : y);
WINDOW_add_content(THIS);
WINDOW_draw_border(THIS, 1);
}
else
{
} else {
WINDOW_draw_border(THIS, 0);
/* as long as we have control over the area taken up (before resize), we shall erase
the whole border */
@ -868,8 +857,7 @@ END_PROPERTY
BEGIN_PROPERTY(Window_Buffered)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnBoolean(THIS->buffered);
return;
}
@ -891,8 +879,7 @@ END_PROPERTY
BEGIN_PROPERTY(Window_CursorX)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(getcurx(THIS->content));
return;
}
@ -903,8 +890,7 @@ END_PROPERTY
BEGIN_PROPERTY(Window_CursorY)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(getcury(THIS->content));
return;
}
@ -915,14 +901,28 @@ END_PROPERTY
BEGIN_PROPERTY(Window_Foreground)
;
short pair;
short f, b;
pair = PAIR_NUMBER(getbkgd(THIS->content));
pair_content(pair, &f, &b);
if (READ_PROPERTY) {
GB.ReturnInteger(f);
return;
}
f = VPROP(GB_INTEGER);
if (!COLOR_VALID(f)) {
GB.Error(GB_ERR_BOUND);
return;
}
COLOR_setpair(pair, f, b);
wbkgd(THIS->content, COLOR_PAIR(pair) | ' ');
END_PROPERTY
BEGIN_PROPERTY(Window_Height)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(getmaxy(THIS->content));
return;
}
@ -934,8 +934,7 @@ END_PROPERTY
BEGIN_PROPERTY(Window_Wrap)
/* This property only affects subsequent prints */
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnBoolean(THIS->wrap);
return;
}
@ -945,8 +944,7 @@ END_PROPERTY
BEGIN_PROPERTY(Window_Width)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(getmaxx(THIS->content));
return;
}
@ -957,8 +955,7 @@ END_PROPERTY
BEGIN_PROPERTY(Window_X)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(getbegx(THIS->main));
return;
}
@ -969,8 +966,7 @@ END_PROPERTY
BEGIN_PROPERTY(Window_Y)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(getbegy(THIS->main));
return;
}
@ -983,8 +979,7 @@ BEGIN_METHOD(Window_new, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h)
WINDOW *new;
if (!NCURSES_RUNNING)
{
if (!NCURSES_RUNNING) {
GB.Error("Not in NCurses mode");
return;
}
@ -995,6 +990,9 @@ BEGIN_METHOD(Window_new, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h)
if (!GB.Parent(_object))
GB.Attach(THIS, (void *) GB.Application.StartupClass(), "Window");
THIS->stream.desc = &WindowStream;
THIS->stream.tag = THIS;
REFRESH();
END_METHOD
@ -1002,8 +1000,10 @@ END_METHOD
BEGIN_METHOD_VOID(Window_free)
WINDOW_remove(THIS);
if (focused == THIS)
if (focused == THIS) {
GB.Watch(0, GB_WATCH_NONE, NULL, 0);
focused = NULL;
}
GB.Detach(THIS);
/* the REFRESH() makes use of THIS so it would be unwise to call that
since we just invalidated it */
@ -1033,15 +1033,13 @@ BEGIN_METHOD(Window_Ask, GB_STRING opts; GB_INTEGER tries)
o = STRING(opts);
while (miss || t--)
{
while (miss || t--) {
ch = getch();
/* Per convention, only dealing with byte chars */
if (ch > 255)
continue;
*c = (char) ch;
if (strchr(o, *c))
{
if (strchr(o, *c)) {
c[1] = 0;
GB.ReturnNewZeroString(c);
return;
@ -1067,9 +1065,9 @@ BEGIN_METHOD_VOID(Window_Cls)
END_METHOD
BEGIN_METHOD_VOID(Window_Flush)
BEGIN_METHOD_VOID(Window_Drain)
WINDOW_flush();
WINDOW_drain();
END_METHOD
@ -1124,8 +1122,7 @@ BEGIN_METHOD(Window_DrawHLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_ST
gx = VARG(x);
gy = VARG(y);
for (i = 0; i < t; i++)
{
for (i = 0; i < t; i++) {
WINDOW_cursor_move(THIS, gx, gy);
whline(THIS->content, c, length);
gy++;
@ -1170,23 +1167,18 @@ BEGIN_METHOD(Window_PrintCenter, GB_STRING text)
char *p, *q;
p = STRING(text);
while ((q = strchr(p, '\n')))
{
while ((q = strchr(p, '\n'))) {
lines++;
p = q + 1;
}
p = STRING(text);
y = (getmaxy(THIS->content) - lines) / 2;
while (lines--)
{
if (!lines)
{
while (lines--) {
if (!lines) {
x = (getmaxx(THIS->content) - strlen(p)) / 2;
WINDOW_print(THIS, p, x, y);
}
else
{
} else {
q = strchr(p, '\n');
*q = 0;
x = (getmaxx(THIS->content) - (q - p)) / 2;
@ -1250,8 +1242,7 @@ BEGIN_METHOD(Window_DrawVLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_ST
gx = VARG(x);
gy = VARG(y);
for (i = 0; i < t; i++)
{
for (i = 0; i < t; i++) {
WINDOW_cursor_move(THIS, gx, gy);
wvline(THIS->content, c, length);
gx++;
@ -1282,7 +1273,7 @@ END_METHOD
BEGIN_PROPERTY(WindowAttrs_Normal)
/* normal is special because it turns off all other attributes and can't itself been turned off */
/* 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))
@ -1318,14 +1309,12 @@ BEGIN_PROPERTY(WindowAttrs_Color)
short pair;
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnInteger(PAIR_NUMBER(getattrs(THIS->content)));
return;
}
pair = VPROP(GB_INTEGER);
if (!PAIR_VALID(pair))
{
if (!PAIR_VALID(pair)) {
GB.Error(GB_ERR_BOUND);
return;
}
@ -1339,8 +1328,7 @@ END_PROPERTY
BEGIN_PROPERTY(CharAttrs_Normal)
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
GB.ReturnBoolean(!WINDOW_char_attrs_driver(THIS, A_NORMAL,
THIS->pos.col, THIS->pos.line, ATTR_DRV_RET));
return;
@ -1381,16 +1369,14 @@ BEGIN_PROPERTY(CharAttrs_Color)
short pair;
if (READ_PROPERTY)
{
if (READ_PROPERTY) {
pair = PAIR_NUMBER(WINDOW_char_attrs_driver(THIS, 0,
THIS->pos.col, THIS->pos.line, ATTR_DRV_RET));
GB.ReturnInteger(pair);
return;
}
pair = VPROP(GB_INTEGER);
if (!PAIR_VALID(pair))
{
if (!PAIR_VALID(pair)) {
GB.Error(GB_ERR_BOUND);
return;
}
@ -1405,6 +1391,7 @@ END_PROPERTY
GB_DESC CWindowDesc[] =
{
GB_DECLARE("Window", sizeof(struct nc_window)),
GB_INHERITS("Stream"),
GB_AUTO_CREATABLE(),
GB_EVENT("Read", NULL, NULL, &EVENT_Read),
@ -1413,7 +1400,7 @@ GB_DESC CWindowDesc[] =
GB_CONSTANT("NoTimeout", "i", TIMEOUT_NOTIMEOUT),
/* Properties */
GB_PROPERTY_READ("Attributes", ".Window.Attrs", Window_Attrs),
GB_PROPERTY_SELF("Attributes", ".Window.Attrs"),
GB_PROPERTY("Background", "i", Window_Background),
GB_PROPERTY("Paper", "i", Window_Background),
@ -1425,7 +1412,7 @@ GB_DESC CWindowDesc[] =
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_READ("ContainerW", "i", Window_ContainerWidth),
GB_PROPERTY("CursorX", "i", Window_CursorX),
GB_PROPERTY("CursorY", "i", Window_CursorY),
@ -1456,7 +1443,7 @@ GB_DESC CWindowDesc[] =
GB_METHOD("Cls", NULL, Window_Cls, NULL),
GB_METHOD("Flush", NULL, Window_Flush, NULL),
GB_METHOD("Drain", NULL, Window_Drain, NULL),
GB_METHOD("Full", NULL, Window_Full, NULL),

View File

@ -43,20 +43,20 @@
/* Translate linear (absolute) memory addresses and x,y coordinates into each other
most useful when wrapping is needed. */
#define A2XY(win, a, x, y) { \
#define A2XY(win, a, x, y) do { \
(x) = (a) % getmaxx(win); \
(y) = (a) / getmaxx(win); \
}
#define XY2A(win, x, y, a) { \
} while (0)
#define XY2A(win, x, y, a) do { \
(a) = (y) * getmaxx(win) + (x); \
}
} while (0)
/* Interpret the -1 values in coordinates as to insert the current cursor position */
#define MAKE_COORDS(win, x, y) { \
#define MAKE_COORDS(win, x, y) do { \
if ((x) == -1) \
x = getcurx(win); \
if ((y) == -1) \
y = getcury(win); \
}
} while (0)
/* Check for out-of-range coordinates */
#define BAD_COORDS(win, x, y) ((x) < 0 || (x) >= getmaxx(win) || \
(y) < 0 || (y) >= getmaxy(win))
@ -76,7 +76,7 @@ enum
ATTR_DRV_COL
};
#define WIN_ATTR_METHOD(b, a) { \
#define WIN_ATTR_METHOD(b, a) do { \
if (READ_PROPERTY) \
GB.ReturnBoolean(WINDOW_attrs_driver( \
THIS, (a), ATTR_DRV_RET) \
@ -84,13 +84,13 @@ enum
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);
} while (0)
#define WIN_ATTR_METHOD_BOOL(a) WIN_ATTR_METHOD(VPROP(GB_BOOLEAN), a)
/* Notice the wtouchln() line in the following macro. It seems that a chgat() from
nc_window_char_attrs_driver() doesn't mark anything dirty (no output on screen from
a REFRESH()). So to make the new attribute available immidiately, we touch the affected
line manually. A higher-callstack function may call REFRESH() to get output. */
#define CHAR_ATTR_METHOD(b, a) { \
#define CHAR_ATTR_METHOD(b, a) do { \
if (READ_PROPERTY) \
GB.ReturnBoolean(WINDOW_char_attrs_driver( \
THIS, (a), THIS->pos.col, THIS->pos.line, \
@ -99,16 +99,16 @@ enum
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);
} while(0)
#define CHAR_ATTR_METHOD_BOOL(a) CHAR_ATTR_METHOD(VPROP(GB_BOOLEAN), a)
#define STREAM_PROLOGUE() void *_object = stream->tag
//TODO: [-] Stream
typedef struct nc_window
{
// [-] background/foreground colors
typedef struct nc_window {
GB_BASE ob;
GB_STREAM stream; /* Gambas stream structure to enable Print #Window, Expr and other stream-related
syntaxes */
GB_STREAM stream; /* Gambas stream structure to enable stream-related syntaxes */
WINDOW *main; /* The main window. */
WINDOW *content; /* This window is used for all content-related operations. Its purpose is turning
the ncurses window borders which are inner-window to outer-window ones thus
@ -119,8 +119,7 @@ typedef struct nc_window
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 */
{
struct { /* This structure is used to pass a line and a column number to virtual objects */
int line;
int col;
} pos;
@ -130,6 +129,7 @@ typedef struct nc_window
extern GB_DESC CWindowDesc[];
extern GB_DESC CWindowAttrsDesc[];
extern GB_DESC CCharAttrsDesc[];
extern GB_STREAM_DESC WindowStream;
#endif
#define WINDOW_main_to_content() WINDOW_copy_window(THIS->main, THIS->content, 0, 0, \