rewrite curses

This commit is contained in:
ruki
2022-11-30 23:22:11 +08:00
parent 941e57a9fd
commit 8c1107932d
11 changed files with 872 additions and 2997 deletions

View File

@@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2016-2018 TBOOX Open Source Group Copyright 2016-present TBOOX Open Source Group
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
A cross-platform terminal ui library based on Lua A cross-platform terminal ui library based on Lua
Copyright 2015-2018 The TBOOX Open Source Group Copyright 2015-present The TBOOX Open Source Group
This product includes software developed by The TBOOX Open Source Group (https://tboox.org/). This product includes software developed by The TBOOX Open Source Group (https://tboox.org/).
@@ -13,12 +13,3 @@ which can be obtained at:
* HOMEPAGE: * HOMEPAGE:
* http://pdcurses.org/ * http://pdcurses.org/
This product depends on 'lcurses/cui', Lua Console User Interface,
which can be obtained at:
* LICENSE:
* core/src/lcurses/LICENSE (MIT License)
* HOMEPAGE:
* http://lua-cui.sourceforge.net/

View File

@@ -24,7 +24,7 @@ build = {
type = "builtin", type = "builtin",
modules = { modules = {
["ltui"] = { ["ltui"] = {
sources = "src/core/lcurses/lcurses.c", sources = "src/core/curses/curses.c",
libraries = {"curses"} libraries = {"curses"}
} }
}, },

865
src/core/curses/curses.c Normal file
View File

@@ -0,0 +1,865 @@
/*!A cross-platform terminal ui library based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2016-present, TBOOX Open Source Group.
*
* @author ruki
* @file curses.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#ifndef LUAJIT
# define LUA_COMPAT_5_1
# define LUA_COMPAT_5_3
# define LUA_COMPAT_ALL
#endif
#include "luaconf.h"
#undef LUA_API
#if defined(__cplusplus)
# define LUA_API extern "C"
#else
# define LUA_API extern
#endif
#ifdef LUAJIT
# include "luajit.h"
#else
# include "lua.h"
#endif
#include "lualib.h"
#include "lauxlib.h"
#include <curses.h>
#if defined(NCURSES_VERSION)
# include <locale.h>
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define LT_CURSES_STDSCR "curses.stdscr"
#define LT_CURSES_WINDOW "curses.window"
#define LT_CURSES_OK(v) (((v) == ERR) ? 0 : 1)
// define functions
#define LT_CURSES_NUMBER(n) \
static int lt_curses_ ## n(lua_State* lua) \
{ \
lua_pushnumber(lua, n()); \
return 1; \
}
#define LT_CURSES_NUMBER2(n, v) \
static int lt_curses_ ## n(lua_State* lua) \
{ \
lua_pushnumber(lua, v); \
return 1; \
}
#define LT_CURSES_BOOL(n) \
static int lt_curses_ ## n(lua_State* lua) \
{ \
lua_pushboolean(lua, n()); \
return 1; \
}
#define LT_CURSES_BOOLOK(n) \
static int lt_curses_ ## n(lua_State* lua) \
{ \
lua_pushboolean(lua, LT_CURSES_OK(n())); \
return 1; \
}
#define LT_CURSES_WINDOW_BOOLOK(n) \
static int lt_curses_window_ ## n(lua_State* lua) \
{ \
WINDOW* w = lt_curses_window_check(lua, 1); \
lua_pushboolean(lua, LT_CURSES_OK(n(w))); \
return 1; \
}
// define constants
#define LT_CURSES_CONST_(n, v) \
lua_pushstring(lua, n); \
lua_pushnumber(lua, v); \
lua_settable(lua, lua_upvalueindex(1));
#define LT_CURSES_CONST(s) LT_CURSES_CONST_(#s, s)
#define LT_CURSES_CONST2(s, v) LT_CURSES_CONST_(#s, v)
// export
#if defined(_WIN32)
# define __export __declspec(dllexport)
#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
# define __export __attribute__((visibility("default")))
#else
# define __export
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
// map key for pdcurses, keeping the keys consistent with ncurses
static int g_mapkey = 0;
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static chtype lt_curses_checkch(lua_State* lua, int index)
{
if (lua_type(lua, index) == LUA_TNUMBER)
return (chtype)luaL_checknumber(lua, index);
if (lua_type(lua, index) == LUA_TSTRING)
return *lua_tostring(lua, index);
#ifdef LUAJIT
luaL_typerror(lua, index, "chtype");
#endif
return (chtype)0;
}
// get character and map key
static int lt_curses_window_getch_impl(WINDOW* w)
{
#ifdef PDCURSES
static int has_key = 0;
static int temp_key = 0;
int key;
if (g_mapkey && has_key)
{
has_key = 0;
return temp_key;
}
key = wgetch(w);
if (key == ERR || !g_mapkey) return key;
if (key >= ALT_A && key <= ALT_Z)
{
has_key = 1;
temp_key = key - ALT_A + 'A';
}
else if (key >= ALT_0 && key <= ALT_9)
{
has_key = 1;
temp_key = key - ALT_0 + '0';
}
else
{
switch (key)
{
case ALT_DEL: temp_key = KEY_DC; break;
case ALT_INS: temp_key = KEY_IC; break;
case ALT_HOME: temp_key = KEY_HOME; break;
case ALT_END: temp_key = KEY_END; break;
case ALT_PGUP: temp_key = KEY_PPAGE; break;
case ALT_PGDN: temp_key = KEY_NPAGE; break;
case ALT_UP: temp_key = KEY_UP; break;
case ALT_DOWN: temp_key = KEY_DOWN; break;
case ALT_RIGHT: temp_key = KEY_RIGHT; break;
case ALT_LEFT: temp_key = KEY_LEFT; break;
case ALT_BKSP: temp_key = KEY_BACKSPACE; break;
default: return key;
}
}
has_key = 1;
return 27;
#else
return wgetch(w);
#endif
}
// new a window object
static void lt_curses_window_new(lua_State* lua, WINDOW* nw)
{
if (nw)
{
WINDOW** w = (WINDOW**)lua_newuserdata(lua, sizeof(WINDOW*));
luaL_getmetatable(lua, LT_CURSES_WINDOW);
lua_setmetatable(lua, -2);
*w = nw;
}
else
{
lua_pushliteral(lua, "failed to create window");
lua_error(lua);
}
}
// get window
static WINDOW** lt_curses_window_get(lua_State* lua, int index)
{
WINDOW** w = (WINDOW**)luaL_checkudata(lua, index, LT_CURSES_WINDOW);
if (w == NULL) luaL_argerror(lua, index, "bad curses window");
return w;
}
// get and check window
static WINDOW* lt_curses_window_check(lua_State* lua, int index)
{
WINDOW** w = lt_curses_window_get(lua, index);
if (*w == NULL) luaL_argerror(lua, index, "attempt to use closed curses window");
return *w;
}
// tostring(window)
static int lt_curses_window_tostring(lua_State* lua)
{
WINDOW** w = lt_curses_window_get(lua, 1);
char const* s = NULL;
if (*w) s = (char const*)lua_touserdata(lua, 1);
lua_pushfstring(lua, "curses window (%s)", s? s : "closed");
return 1;
}
// window:move(y, x)
static int lt_curses_window_move(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int y = luaL_checkint(lua, 2);
int x = luaL_checkint(lua, 3);
lua_pushboolean(lua, LT_CURSES_OK(wmove(w, y, x)));
return 1;
}
// window:getyx(y, x)
static int lt_curses_window_getyx(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int y, x;
getyx(w, y, x);
lua_pushnumber(lua, y);
lua_pushnumber(lua, x);
return 2;
}
// window:getmaxyx(y, x)
static int lt_curses_window_getmaxyx(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int y, x;
getmaxyx(w, y, x);
lua_pushnumber(lua, y);
lua_pushnumber(lua, x);
return 2;
}
// window:delwin()
static int lt_curses_window_delwin(lua_State* lua)
{
WINDOW** w = lt_curses_window_get(lua, 1);
if (*w && *w != stdscr)
{
delwin(*w);
*w = NULL;
}
return 0;
}
// window:addch(ch)
static int lt_curses_window_addch(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
chtype ch = lt_curses_checkch(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(waddch(w, ch)));
return 1;
}
// window:addnstr(str)
static int lt_curses_window_addnstr(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
const char* str = luaL_checkstring(lua, 2);
int n = luaL_optint(lua, 3, -1);
if (n < 0) n = (int)lua_strlen(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(waddnstr(w, str, n)));
return 1;
}
// window:keypad(true)
static int lt_curses_window_keypad(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int enabled = lua_isnoneornil(lua, 2) ? 1 : lua_toboolean(lua, 2);
if (enabled)
{
// on WIN32 ALT keys need to be mapped, so to make sure you get the wanted keys,
// only makes sense when using keypad(true) and echo(false)
g_mapkey = 1;
}
lua_pushboolean(lua, LT_CURSES_OK(keypad(w, enabled)));
return 1;
}
// window:meta(true)
static int lt_curses_window_meta(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int enabled = lua_toboolean(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(meta(w, enabled)));
return 1;
}
// window:nodelay(true)
static int lt_curses_window_nodelay(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int enabled = lua_toboolean(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(nodelay(w, enabled)));
return 1;
}
// window:leaveok(true)
static int lt_curses_window_leaveok(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int enabled = lua_toboolean(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(leaveok(w, enabled)));
return 1;
}
// window:getch()
static int lt_curses_window_getch(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int c = lt_curses_window_getch_impl(w);
if (c == ERR) return 0;
lua_pushnumber(lua, c);
return 1;
}
// window:attroff(attrs)
static int lt_curses_window_attroff(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int attrs = luaL_checkint(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(wattroff(w, attrs)));
return 1;
}
// window:attron(attrs)
static int lt_curses_window_attron(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int attrs = luaL_checkint(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(wattron(w, attrs)));
return 1;
}
// window:attrset(attrs)
static int lt_curses_window_attrset(lua_State* lua)
{
WINDOW* w = lt_curses_window_check(lua, 1);
int attrs = luaL_checkint(lua, 2);
lua_pushboolean(lua, LT_CURSES_OK(wattrset(w, attrs)));
return 1;
}
// window:copywin(...)
static int lt_curses_window_copywin(lua_State* lua)
{
WINDOW* srcwin = lt_curses_window_check(lua, 1);
WINDOW* dstwin = lt_curses_window_check(lua, 2);
int sminrow = luaL_checkint(lua, 3);
int smincol = luaL_checkint(lua, 4);
int dminrow = luaL_checkint(lua, 5);
int dmincol = luaL_checkint(lua, 6);
int dmaxrow = luaL_checkint(lua, 7);
int dmaxcol = luaL_checkint(lua, 8);
int overlay = lua_toboolean(lua, 9);
lua_pushboolean(lua, LT_CURSES_OK(copywin(srcwin, dstwin, sminrow,
smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay)));
return 1;
}
// clean window after exiting program
static void lt_curses_cleanup()
{
if (!isendwin())
{
wclear(stdscr);
wrefresh(stdscr);
endwin();
}
}
// register constants
static void lt_curses_register_constants(lua_State* lua)
{
// colors
LT_CURSES_CONST(COLOR_BLACK)
LT_CURSES_CONST(COLOR_RED)
LT_CURSES_CONST(COLOR_GREEN)
LT_CURSES_CONST(COLOR_YELLOW)
LT_CURSES_CONST(COLOR_BLUE)
LT_CURSES_CONST(COLOR_MAGENTA)
LT_CURSES_CONST(COLOR_CYAN)
LT_CURSES_CONST(COLOR_WHITE)
// alternate character set
LT_CURSES_CONST(ACS_BLOCK)
LT_CURSES_CONST(ACS_BOARD)
LT_CURSES_CONST(ACS_BTEE)
LT_CURSES_CONST(ACS_TTEE)
LT_CURSES_CONST(ACS_LTEE)
LT_CURSES_CONST(ACS_RTEE)
LT_CURSES_CONST(ACS_LLCORNER)
LT_CURSES_CONST(ACS_LRCORNER)
LT_CURSES_CONST(ACS_URCORNER)
LT_CURSES_CONST(ACS_ULCORNER)
LT_CURSES_CONST(ACS_LARROW)
LT_CURSES_CONST(ACS_RARROW)
LT_CURSES_CONST(ACS_UARROW)
LT_CURSES_CONST(ACS_DARROW)
LT_CURSES_CONST(ACS_HLINE)
LT_CURSES_CONST(ACS_VLINE)
LT_CURSES_CONST(ACS_BULLET)
LT_CURSES_CONST(ACS_CKBOARD)
LT_CURSES_CONST(ACS_LANTERN)
LT_CURSES_CONST(ACS_DEGREE)
LT_CURSES_CONST(ACS_DIAMOND)
LT_CURSES_CONST(ACS_PLMINUS)
LT_CURSES_CONST(ACS_PLUS)
LT_CURSES_CONST(ACS_S1)
LT_CURSES_CONST(ACS_S9)
// attributes
LT_CURSES_CONST(A_NORMAL)
LT_CURSES_CONST(A_STANDOUT)
LT_CURSES_CONST(A_UNDERLINE)
LT_CURSES_CONST(A_REVERSE)
LT_CURSES_CONST(A_BLINK)
LT_CURSES_CONST(A_DIM)
LT_CURSES_CONST(A_BOLD)
LT_CURSES_CONST(A_PROTECT)
LT_CURSES_CONST(A_INVIS)
LT_CURSES_CONST(A_ALTCHARSET)
LT_CURSES_CONST(A_CHARTEXT)
// key functions
LT_CURSES_CONST(KEY_BREAK)
LT_CURSES_CONST(KEY_DOWN)
LT_CURSES_CONST(KEY_UP)
LT_CURSES_CONST(KEY_LEFT)
LT_CURSES_CONST(KEY_RIGHT)
LT_CURSES_CONST(KEY_HOME)
LT_CURSES_CONST(KEY_BACKSPACE)
LT_CURSES_CONST(KEY_DL)
LT_CURSES_CONST(KEY_IL)
LT_CURSES_CONST(KEY_DC)
LT_CURSES_CONST(KEY_IC)
LT_CURSES_CONST(KEY_EIC)
LT_CURSES_CONST(KEY_CLEAR)
LT_CURSES_CONST(KEY_EOS)
LT_CURSES_CONST(KEY_EOL)
LT_CURSES_CONST(KEY_SF)
LT_CURSES_CONST(KEY_SR)
LT_CURSES_CONST(KEY_NPAGE)
LT_CURSES_CONST(KEY_PPAGE)
LT_CURSES_CONST(KEY_STAB)
LT_CURSES_CONST(KEY_CTAB)
LT_CURSES_CONST(KEY_CATAB)
LT_CURSES_CONST(KEY_ENTER)
LT_CURSES_CONST(KEY_SRESET)
LT_CURSES_CONST(KEY_RESET)
LT_CURSES_CONST(KEY_PRINT)
LT_CURSES_CONST(KEY_LL)
LT_CURSES_CONST(KEY_A1)
LT_CURSES_CONST(KEY_A3)
LT_CURSES_CONST(KEY_B2)
LT_CURSES_CONST(KEY_C1)
LT_CURSES_CONST(KEY_C3)
LT_CURSES_CONST(KEY_BTAB)
LT_CURSES_CONST(KEY_BEG)
LT_CURSES_CONST(KEY_CANCEL)
LT_CURSES_CONST(KEY_CLOSE)
LT_CURSES_CONST(KEY_COMMAND)
LT_CURSES_CONST(KEY_COPY)
LT_CURSES_CONST(KEY_CREATE)
LT_CURSES_CONST(KEY_END)
LT_CURSES_CONST(KEY_EXIT)
LT_CURSES_CONST(KEY_FIND)
LT_CURSES_CONST(KEY_HELP)
LT_CURSES_CONST(KEY_MARK)
LT_CURSES_CONST(KEY_MESSAGE)
#ifdef PDCURSES
// https://github.com/xmake-io/xmake/issues/1610#issuecomment-971149885
LT_CURSES_CONST(KEY_C2)
LT_CURSES_CONST(KEY_A2)
LT_CURSES_CONST(KEY_B1)
LT_CURSES_CONST(KEY_B3)
#endif
#if !defined(XCURSES)
# ifndef NOMOUSE
LT_CURSES_CONST(KEY_MOUSE)
# endif
#endif
LT_CURSES_CONST(KEY_MOVE)
LT_CURSES_CONST(KEY_NEXT)
LT_CURSES_CONST(KEY_OPEN)
LT_CURSES_CONST(KEY_OPTIONS)
LT_CURSES_CONST(KEY_PREVIOUS)
LT_CURSES_CONST(KEY_REDO)
LT_CURSES_CONST(KEY_REFERENCE)
LT_CURSES_CONST(KEY_REFRESH)
LT_CURSES_CONST(KEY_REPLACE)
LT_CURSES_CONST(KEY_RESIZE)
LT_CURSES_CONST(KEY_RESTART)
LT_CURSES_CONST(KEY_RESUME)
LT_CURSES_CONST(KEY_SAVE)
LT_CURSES_CONST(KEY_SBEG)
LT_CURSES_CONST(KEY_SCANCEL)
LT_CURSES_CONST(KEY_SCOMMAND)
LT_CURSES_CONST(KEY_SCOPY)
LT_CURSES_CONST(KEY_SCREATE)
LT_CURSES_CONST(KEY_SDC)
LT_CURSES_CONST(KEY_SDL)
LT_CURSES_CONST(KEY_SELECT)
LT_CURSES_CONST(KEY_SEND)
LT_CURSES_CONST(KEY_SEOL)
LT_CURSES_CONST(KEY_SEXIT)
LT_CURSES_CONST(KEY_SFIND)
LT_CURSES_CONST(KEY_SHELP)
LT_CURSES_CONST(KEY_SHOME)
LT_CURSES_CONST(KEY_SIC)
LT_CURSES_CONST(KEY_SLEFT)
LT_CURSES_CONST(KEY_SMESSAGE)
LT_CURSES_CONST(KEY_SMOVE)
LT_CURSES_CONST(KEY_SNEXT)
LT_CURSES_CONST(KEY_SOPTIONS)
LT_CURSES_CONST(KEY_SPREVIOUS)
LT_CURSES_CONST(KEY_SPRINT)
LT_CURSES_CONST(KEY_SREDO)
LT_CURSES_CONST(KEY_SREPLACE)
LT_CURSES_CONST(KEY_SRIGHT)
LT_CURSES_CONST(KEY_SRSUME)
LT_CURSES_CONST(KEY_SSAVE)
LT_CURSES_CONST(KEY_SSUSPEND)
LT_CURSES_CONST(KEY_SUNDO)
LT_CURSES_CONST(KEY_SUSPEND)
LT_CURSES_CONST(KEY_UNDO)
// KEY_Fx 0 <= x <= 63
LT_CURSES_CONST(KEY_F0)
LT_CURSES_CONST2(KEY_F1, KEY_F(1))
LT_CURSES_CONST2(KEY_F2, KEY_F(2))
LT_CURSES_CONST2(KEY_F3, KEY_F(3))
LT_CURSES_CONST2(KEY_F4, KEY_F(4))
LT_CURSES_CONST2(KEY_F5, KEY_F(5))
LT_CURSES_CONST2(KEY_F6, KEY_F(6))
LT_CURSES_CONST2(KEY_F7, KEY_F(7))
LT_CURSES_CONST2(KEY_F8, KEY_F(8))
LT_CURSES_CONST2(KEY_F9, KEY_F(9))
LT_CURSES_CONST2(KEY_F10, KEY_F(10))
LT_CURSES_CONST2(KEY_F11, KEY_F(11))
LT_CURSES_CONST2(KEY_F12, KEY_F(12))
#if !defined(XCURSES)
# ifndef NOMOUSE
// mouse constants
LT_CURSES_CONST(BUTTON1_RELEASED)
LT_CURSES_CONST(BUTTON1_PRESSED)
LT_CURSES_CONST(BUTTON1_CLICKED)
LT_CURSES_CONST(BUTTON1_DOUBLE_CLICKED)
LT_CURSES_CONST(BUTTON1_TRIPLE_CLICKED)
LT_CURSES_CONST(BUTTON2_RELEASED)
LT_CURSES_CONST(BUTTON2_PRESSED)
LT_CURSES_CONST(BUTTON2_CLICKED)
LT_CURSES_CONST(BUTTON2_DOUBLE_CLICKED)
LT_CURSES_CONST(BUTTON2_TRIPLE_CLICKED)
LT_CURSES_CONST(BUTTON3_RELEASED)
LT_CURSES_CONST(BUTTON3_PRESSED)
LT_CURSES_CONST(BUTTON3_CLICKED)
LT_CURSES_CONST(BUTTON3_DOUBLE_CLICKED)
LT_CURSES_CONST(BUTTON3_TRIPLE_CLICKED)
LT_CURSES_CONST(BUTTON4_RELEASED)
LT_CURSES_CONST(BUTTON4_PRESSED)
LT_CURSES_CONST(BUTTON4_CLICKED)
LT_CURSES_CONST(BUTTON4_DOUBLE_CLICKED)
LT_CURSES_CONST(BUTTON4_TRIPLE_CLICKED)
LT_CURSES_CONST(BUTTON_CTRL)
LT_CURSES_CONST(BUTTON_SHIFT)
LT_CURSES_CONST(BUTTON_ALT)
LT_CURSES_CONST(REPORT_MOUSE_POSITION)
LT_CURSES_CONST(ALL_MOUSE_EVENTS)
# if NCURSES_MOUSE_VERSION > 1
LT_CURSES_CONST(BUTTON5_RELEASED)
LT_CURSES_CONST(BUTTON5_PRESSED)
LT_CURSES_CONST(BUTTON5_CLICKED)
LT_CURSES_CONST(BUTTON5_DOUBLE_CLICKED)
LT_CURSES_CONST(BUTTON5_TRIPLE_CLICKED)
# else
LT_CURSES_CONST(BUTTON1_RESERVED_EVENT)
LT_CURSES_CONST(BUTTON2_RESERVED_EVENT)
LT_CURSES_CONST(BUTTON3_RESERVED_EVENT)
LT_CURSES_CONST(BUTTON4_RESERVED_EVENT)
# endif
# endif
#endif
}
// init curses
static int lt_curses_initscr(lua_State* lua)
{
WINDOW* w = initscr();
if (!w) return 0;
lt_curses_window_new(lua, w);
#if defined(NCURSES_VERSION)
ESCDELAY = 0;
#endif
lua_pushstring(lua, LT_CURSES_STDSCR);
lua_pushvalue(lua, -2);
lua_rawset(lua, LUA_REGISTRYINDEX);
lt_curses_register_constants(lua);
#ifndef PDCURSES
atexit(lt_curses_cleanup);
#endif
return 1;
}
static int lt_curses_endwin(lua_State* lua)
{
endwin();
#ifdef XCURSES
XCursesExit();
exit(0);
#endif
return 0;
}
static int lt_curses_stdscr(lua_State* lua)
{
lua_pushstring(lua, LT_CURSES_STDSCR);
lua_rawget(lua, LUA_REGISTRYINDEX);
return 1;
}
#if !defined(XCURSES) && !defined(NOMOUSE)
static int lt_curses_getmouse(lua_State* lua)
{
MEVENT e;
if (getmouse(&e) == OK)
{
lua_pushinteger(lua, e.bstate);
lua_pushinteger(lua, e.x);
lua_pushinteger(lua, e.y);
lua_pushinteger(lua, e.z);
lua_pushinteger(lua, e.id);
return 5;
}
lua_pushnil(lua);
return 1;
}
static int lt_curses_mousemask(lua_State* lua)
{
mmask_t m = luaL_checkint(lua, 1);
mmask_t om;
m = mousemask(m, &om);
lua_pushinteger(lua, m);
lua_pushinteger(lua, om);
return 2;
}
#endif
static int lt_curses_init_pair(lua_State* lua)
{
short pair = luaL_checkint(lua, 1);
short f = luaL_checkint(lua, 2);
short b = luaL_checkint(lua, 3);
lua_pushboolean(lua, LT_CURSES_OK(init_pair(pair, f, b)));
return 1;
}
static int lt_curses_COLOR_PAIR(lua_State* lua)
{
int n = luaL_checkint(lua, 1);
lua_pushnumber(lua, COLOR_PAIR(n));
return 1;
}
static int lt_curses_curs_set(lua_State* lua)
{
int vis = luaL_checkint(lua, 1);
int state = curs_set(vis);
if (state == ERR)
return 0;
lua_pushnumber(lua, state);
return 1;
}
static int lt_curses_napms(lua_State* lua)
{
int ms = luaL_checkint(lua, 1);
lua_pushboolean(lua, LT_CURSES_OK(napms(ms)));
return 1;
}
static int lt_curses_cbreak(lua_State* lua)
{
if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1))
lua_pushboolean(lua, LT_CURSES_OK(cbreak()));
else
lua_pushboolean(lua, LT_CURSES_OK(nocbreak()));
return 1;
}
static int lt_curses_echo(lua_State* lua)
{
if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1))
lua_pushboolean(lua, LT_CURSES_OK(echo()));
else
lua_pushboolean(lua, LT_CURSES_OK(noecho()));
return 1;
}
static int lt_curses_nl(lua_State* lua)
{
if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1))
lua_pushboolean(lua, LT_CURSES_OK(nl()));
else
lua_pushboolean(lua, LT_CURSES_OK(nonl()));
return 1;
}
static int lt_curses_newpad(lua_State* lua)
{
int nlines = luaL_checkint(lua, 1);
int ncols = luaL_checkint(lua, 2);
lt_curses_window_new(lua, newpad(nlines, ncols));
return 1;
}
LT_CURSES_NUMBER2(COLS, COLS)
LT_CURSES_NUMBER2(LINES, LINES)
LT_CURSES_BOOL(isendwin)
LT_CURSES_BOOLOK(start_color)
LT_CURSES_BOOL(has_colors)
LT_CURSES_BOOLOK(doupdate)
LT_CURSES_WINDOW_BOOLOK(wclear)
LT_CURSES_WINDOW_BOOLOK(wnoutrefresh)
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
static const luaL_Reg g_window_functions[] =
{
{ "close", lt_curses_window_delwin },
{ "keypad", lt_curses_window_keypad },
{ "meta", lt_curses_window_meta },
{ "nodelay", lt_curses_window_nodelay },
{ "leaveok", lt_curses_window_leaveok },
{ "move", lt_curses_window_move },
{ "clear", lt_curses_window_wclear },
{ "noutrefresh",lt_curses_window_wnoutrefresh },
{ "attroff", lt_curses_window_attroff },
{ "attron", lt_curses_window_attron },
{ "attrset", lt_curses_window_attrset },
{ "getch", lt_curses_window_getch },
{ "getyx", lt_curses_window_getyx },
{ "getmaxyx", lt_curses_window_getmaxyx },
{ "addch", lt_curses_window_addch },
{ "addstr", lt_curses_window_addnstr },
{ "copy", lt_curses_window_copywin },
{"__gc", lt_curses_window_delwin },
{"__tostring", lt_curses_window_tostring },
{NULL, NULL }
};
static const luaL_Reg g_curses_functions[] =
{
{ "done", lt_curses_endwin },
{ "isdone", lt_curses_isendwin },
{ "main_window", lt_curses_stdscr },
{ "columns", lt_curses_COLS },
{ "lines", lt_curses_LINES },
{ "start_color", lt_curses_start_color },
{ "has_colors", lt_curses_has_colors },
{ "init_pair", lt_curses_init_pair },
{ "color_pair", lt_curses_COLOR_PAIR },
{ "napms", lt_curses_napms },
{ "cursor_set", lt_curses_curs_set },
{ "new_pad", lt_curses_newpad },
{ "doupdate", lt_curses_doupdate },
{ "cbreak", lt_curses_cbreak },
{ "echo", lt_curses_echo },
{ "nl", lt_curses_nl },
#if !defined(XCURSES)
#ifndef NOMOUSE
{ "mousemask", lt_curses_mousemask },
{ "getmouse", lt_curses_getmouse },
#endif
#endif
{NULL, NULL}
};
/* //////////////////////////////////////////////////////////////////////////////////////
* implementations
*/
#ifdef __cplusplus
extern "C" {
#endif
__export int luaopen_ltui_lcurses(lua_State* lua)
{
// create new metatable for window objects
luaL_newmetatable(lua, LT_CURSES_WINDOW);
lua_pushliteral(lua, "__index");
lua_pushvalue(lua, -2); /* push metatable */
lua_rawset(lua, -3); /* metatable.__index = metatable */
luaL_setfuncs(lua, g_window_functions, 0);
lua_pop(lua, 1); /* remove metatable from stack */
// create global table with curses methods/variables/constants
lua_newtable(lua);
luaL_setfuncs(lua, g_curses_functions, 0);
// add curses.init()
lua_pushstring(lua, "init");
lua_pushvalue(lua, -2);
lua_pushcclosure(lua, lt_curses_initscr, 1);
lua_settable(lua, -3);
/* Since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function.
* That means that you have to call setlocale() in the application and encode Unicode strings using one of the systems available encodings.
*
* And we need link libncursesw.so for drawing vline, hline characters
*/
#if defined(NCURSES_VERSION)
setlocale(LC_ALL, "");
#endif
return 1;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,3 @@
target("ltui")
add_files("curses.c", {languages = "c99", cflags = "-Wno-expansion-to-defined"})

View File

@@ -1,20 +0,0 @@
Author: Tiago Dionizio <tiago.dionizio (AT) gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -1,358 +0,0 @@
/************************************************************************
* Author : Tiago Dionizio (tngd@mega.ist.utl.pt) *
* Library : lcurses - Lua 5 interface to the curses library *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
************************************************************************/
/************************************************************************
$Id: lpanel.c 17 2007-06-21 15:30:45Z tngd $
Changes:
************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include <panel.h>
/*
** =======================================================
** defines
** =======================================================
*/
#define PANELMETA "curses:panel"
#define UPINDEX LUA_ENVIRONINDEX
/* ======================================================= */
#define LCP_BOOLOK(n) \
static int lcp_ ## n(lua_State *L) \
{ \
PANEL *p = lcp_check(L, 1); \
lua_pushboolean(L, B(n(p))); \
return 1; \
}
/*
** =======================================================
** privates
** =======================================================
*/
static void lcp_new(lua_State *L, PANEL *np)
{
if (np)
{
PANEL **p = lua_newuserdata(L, sizeof(PANEL*));
luaL_getmetatable(L, PANELMETA);
lua_setmetatable(L, -2);
*p = np;
}
else
{
lua_pushliteral(L, "failed to create panel");
lua_error(L);
}
}
static PANEL *lcp_check(lua_State *L, int index)
{
PANEL **p = (PANEL**)luaL_checkudata(L, 1, PANELMETA);
if (p == NULL) luaL_argerror(L, index, "bad curses panel");
if (*p == NULL) luaL_argerror(L, index, "attempt to use closed curses panel");
return *p;
}
static PANEL **lcp_get(lua_State *L, int index)
{
PANEL **p = (PANEL**)luaL_checkudata(L, 1, PANELMETA);
if (p == NULL) luaL_argerror(L, index, "bad curses panel");
return p;
}
static int lcp_tostring(lua_State *L)
{
PANEL **p = lcp_get(L, 1);
char buff[34];
if (*p == NULL)
strcpy(buff, "closed");
else
sprintf(buff, "%p", lua_touserdata(L, 1));
lua_pushfstring(L, "curses panel (%s)", buff);
return 1;
}
/*
** =======================================================
** panel
** =======================================================
*/
static int lc_new_panel(lua_State *L)
{
WINDOW *w = lcw_check(L, 1);
lcp_new(L, new_panel(w));
/* save window userdata for future use if needed */
lua_pushlightuserdata(L, w);
lua_pushvalue(L, 1);
lua_rawset(L, UPINDEX);
/* save panel userdata for future use if needed */
lua_pushlightuserdata(L, *(PANEL**)lua_touserdata(L, 2));
lua_pushvalue(L, -2);
lua_rawset(L, UPINDEX);
return 1;
}
static int lcp_del_panel(lua_State *L)
{
PANEL **p = lcp_get(L, 1);
if (*p != NULL)
{
/* remove information associated with panel */
/* remove panel userdata entry */
lua_pushlightuserdata(L, *p);
lua_pushnil(L);
lua_rawset(L, UPINDEX);
/* remove associated window */
lua_pushlightuserdata(L, panel_window(*p));
lua_pushnil(L);
lua_rawset(L, UPINDEX);
/* remove panel user data entry */
lua_pushvalue(L, 1);
lua_pushnil(L);
lua_rawset(L, UPINDEX);
del_panel(*p);
*p = NULL;
}
return 0;
}
LCP_BOOLOK(bottom_panel)
LCP_BOOLOK(top_panel)
static int lcp_show_panel(lua_State *L)
{
PANEL *p = lcp_check(L, 1);
if (lua_isnoneornil(L, 2) || lua_toboolean(L, 2))
lua_pushboolean(L, B(show_panel(p)));
else
lua_pushboolean(L, B(hide_panel(p)));
return 1;
}
/*LCP_BOOLOK(show_panel)*/
LCP_BOOLOK(hide_panel)
LCP_BOOLOK(panel_hidden)
static int lc_update_panels(lua_State *L)
{
update_panels();
return 0;
}
static int lcp_panel_window(lua_State *L)
{
PANEL *p = lcp_check(L, 1);
WINDOW *w = panel_window(p);
/* get window userdata */
lua_pushlightuserdata(L, w);
lua_rawget(L, UPINDEX);
return 1;
}
static int lcp_replace_panel(lua_State *L)
{
PANEL *p = lcp_check(L, 1);
WINDOW *w = lcw_check(L, 2);
WINDOW *oldw = panel_window(p);
if (replace_panel(p, w) == ERR)
{
lua_pushboolean(L, 0);
return 1;
}
/* remove entry of old window */
lua_pushlightuserdata(L, oldw);
lua_pushnil(L);
lua_rawset(L, UPINDEX);
/* and save new window */
lua_pushlightuserdata(L, oldw);
lua_pushvalue(L, 2);
lua_rawset(L, UPINDEX);
lua_pushboolean(L, 1);
return 1;
}
static int lcp_move_panel(lua_State *L)
{
PANEL *p = lcp_check(L, 1);
int starty = luaL_checkint(L, 2);
int startx = luaL_checkint(L, 3);
lua_pushboolean(L, B(move_panel(p, starty, startx)));
return 1;
}
static int lc_bottom_panel(lua_State *L)
{
PANEL *ap = panel_above(NULL);
/* get associated userdata variable */
lua_pushlightuserdata(L, ap);
lua_rawget(L, UPINDEX);
return 1;
}
static int lcp_panel_above(lua_State *L)
{
PANEL *p = lcp_check(L, 1);
PANEL *ap = panel_above(p);
/* get associated userdata variable */
lua_pushlightuserdata(L, ap);
lua_rawget(L, UPINDEX);
return 1;
}
static int lc_top_panel(lua_State *L)
{
PANEL *bp = panel_below(NULL);
/* get associated userdata variable */
lua_pushlightuserdata(L, bp);
lua_rawget(L, UPINDEX);
return 1;
}
static int lcp_panel_below(lua_State *L)
{
PANEL *p = lcp_check(L, 1);
PANEL *bp = panel_below(p);
/* get associated userdata variable */
lua_pushlightuserdata(L, bp);
lua_rawget(L, UPINDEX);
return 1;
}
static int lcp_set_panel_userptr(lua_State *L)
{
lcp_check(L, 1);
/* instead of checkinf if we have a user data value,
** force it's existance without any side effects */
lua_settop(L, 2);
lua_rawset(L, UPINDEX);
return 1;
}
static int lcp_panel_userptr(lua_State *L)
{
lcp_check(L, 1);
lua_pushvalue(L, 1);
lua_rawget(L, UPINDEX);
return 1;
}
/* ======================================================= */
#define EPF(name) { #name, lcp_ ## name },
static const luaL_reg panellib[] =
{
/* panel */
{ "close", lcp_del_panel },
{ "make_bottom", lcp_bottom_panel },
{ "make_top", lcp_top_panel },
{ "show", lcp_show_panel },
{ "hide", lcp_hide_panel },
{ "hidden", lcp_panel_hidden },
{ "window", lcp_panel_window },
{ "replace", lcp_replace_panel },
{ "move", lcp_move_panel },
{ "above", lcp_panel_above },
{ "below", lcp_panel_below },
{ "set_userdata", lcp_set_panel_userptr },
{ "userdata", lcp_panel_userptr },
/* misc */
{"__gc", lcp_del_panel}, /* rough safety net */
{"__tostring", lcp_tostring},
{NULL, NULL}
};
#define ECF(name) { #name, lc_ ## name },
static const luaL_reg cursespanellib[] =
{
/* panel */
ECF(new_panel)
ECF(update_panels)
ECF(bottom_panel)
ECF(top_panel)
/* terminator */
{NULL, NULL}
};
/*
** TODO: add upvalue table with lightuserdata keys and weak keyed
** values containing WINDOWS and PANELS used in above functions
*/
int PANEL_EP (lua_State *L)
{
/* metatable with used panels and associated windows */
lua_newtable(L);
/*
** create new metatable for window objects
*/
luaL_newmetatable(L, PANELMETA);
lua_pushliteral(L, "__index");
lua_pushvalue(L, -2); /* push metatable */
lua_rawset(L, -3); /* metatable.__index = metatable */
lua_pushvalue(L, -2); /* upvalue table */
luaL_openlib(L, NULL, panellib, 1);
lua_pop(L, 1); /* remove metatable from stack */
/*
** create global table with curses methods/variables/constants
*/
luaL_openlib(L, NULL, cursespanellib, 1);
return 1;
}

View File

@@ -1,5 +0,0 @@
target("ltui")
-- add source files
add_files("lcurses.c", {languages = "c99", cflags = "-Wno-expansion-to-defined"})

View File

@@ -51,14 +51,6 @@ function program:init(name, argv)
curses.mousemask(curses.ALL_MOUSE_EVENTS) curses.mousemask(curses.ALL_MOUSE_EVENTS)
end end
-- to filter characters being output to the screen
-- this will filter all characters where a chtype or chstr is used
curses.map_output(true)
-- on WIN32 ALT keys need to be mapped, so to make sure you get the wanted keys,
-- only makes sense when using keypad(true) and echo(false)
curses.map_keyboard(true)
-- init colors -- init colors
if (curses.has_colors()) then if (curses.has_colors()) then
curses.start_color() curses.start_color()

View File

@@ -131,7 +131,7 @@ target("ltui")
end end
-- add projects -- add projects
includes("src/core/lcurses") includes("src/core/curses")
if is_plat("windows") then if is_plat("windows") then
includes("src/core/pdcurses") includes("src/core/pdcurses")
end end