diff --git a/goldlib/gcui/Makefile b/goldlib/gcui/Makefile new file mode 100644 index 0000000..fa8b34e --- /dev/null +++ b/goldlib/gcui/Makefile @@ -0,0 +1,37 @@ +## ------------------------------------------------------------------- +## The Goldware Library. Copyright (C) Odinn Sorensen and Golded+ team +## ------------------------------------------------------------------- +## GCUI: Golded+ Character-oriented User Interface library. +## ------------------------------------------------------------------- +# -*- makefile -*- +# Build library using GNU make and CNU C++ compuler. + +ifeq ($(TERM),cygwin) +MINGW=true +else +ifeq ($(OSTYPE),msys) +MINGW=true +endif +endif + +TOP=../.. +TARGET=gcui +INCS=-I$(TOP)/goldlib/gcui -I$(TOP)/goldlib/gall +ifeq ($(PLATFORM),emx) || ($(PLATFORM),MINGW) +INCS+=-I$(TOP)/goldlib/glibc +endif + +include $(TOP)/Config.def +ifneq ($(findstring GCFG_NO_MYSPELL, $(CPPFLAGS)), GCFG_NO_MYSPELL) +INCS+=-I$(TOP)/goldlib/hunspell +endif + +include $(TOP)/GNUmakef.inc + +ifeq ($(PLATFORM),emx) +ifeq ($(AR),emxomfar) +AR += -p32 +endif +endif + +include $(TOP)/GNUmakef.lib diff --git a/goldlib/gcui/gcui.all b/goldlib/gcui/gcui.all new file mode 100644 index 0000000..e18686b --- /dev/null +++ b/goldlib/gcui/gcui.all @@ -0,0 +1,53 @@ +## ------------------------------------------------------------------- +## The Goldware Library. Copyright (C) Odinn Sorensen and Golded+ team +## ------------------------------------------------------------------- +## 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 of the +## License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## ------------------------------------------------------------------- +## $Id$ +## ------------------------------------------------------------------- +## GCUI: Golded+ Character-oriented User Interface. +## Master build file for GCUI. +## ------------------------------------------------------------------- + +## Keyboard. +gkbdbase cpp all nov bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gkbdgetm cpp all nov bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gkbdwait cpp all nov bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx + +## Text searching. +gsrchmgr cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx + +## Mouse. +gmoubase cpp all nov bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx + +## Low-level text video +gvidbase cpp all nov bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gvidinit cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx + +## Text windowing. +gwinbase cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwindow cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinhlp1 cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinhlp2 cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwininit cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinline cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinmenu cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinmnub cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinpckf cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinpcks cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinpick cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx +gwinput2 cpp all ovl bcd bco bcx wcn wco wcx lnx emx djg rsx cyg be sun osx + +## ------------------------------------------------------------------ diff --git a/goldlib/gcui/gcurses.h b/goldlib/gcui/gcurses.h new file mode 100644 index 0000000..d7f1bb2 --- /dev/null +++ b/goldlib/gcui/gcurses.h @@ -0,0 +1,253 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1989 Free Software Foundation +// Copyright (C) 2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// This file is derived from the GNU C++ Library. +// Written by Eric Newton (newton@rocky.oswego.edu) +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Declarations for ncurses. +// ------------------------------------------------------------------ + +#ifndef __gcurses_h +#define __gcurses_h + +// ------------------------------------------------------------------ + +// Even many system which mostly have C++-ready header files, +// do not have C++-ready curses.h. +extern "C" { +#if defined(__FreeBSD__) && (__FreeBSD__ < 4) +#include +#elif defined(__sun__) +#include +#else +#include +#endif +} + + +// ------------------------------------------------------------------ + +// "Convert" macros to inlines, if needed. +#ifdef addch +inline int (addch)(char ch) { return addch(ch); } +#undef addch +#endif +#ifdef addstr +// The (char*) cast is to hack around missing const's +inline int (addstr)(const char * str) { return addstr((char*)str); } +#undef addstr +#endif +#ifdef clear +inline int (clear)() { return clear(); } +#undef clear +#endif +#ifdef clearok +inline int (clearok)(WINDOW* win, bool bf) { return clearok(win, bf); } +#undef clearok +#else +extern "C" int clearok(WINDOW*, bool); +#endif +#ifdef clrtobot +inline int (clrtobot)() { return clrtobot(); } +#undef clrtobot +#endif +#ifdef clrtoeol +inline int (clrtoeol)() { return clrtoeol(); } +#undef clrtoeol +#endif +#ifdef delch +inline int (delch)() { return delch(); } +#undef delch +#endif +#ifdef deleteln +inline int (deleteln)() { return deleteln(); } +#undef deleteln +#endif +#ifdef erase +inline int (erase)() { return erase(); } +#undef erase +#endif +#ifdef flushok +inline int (flushok)(WINDOW* _win, int _bf) { return flushok(_win, _bf); } +#undef flushok +#else +#define _no_flushok +#endif +#ifdef getch +inline int (getch)() { return getch(); } +#undef getch +#endif +#ifdef getstr +inline int (getstr)(char *_str) { return getstr(_str); } +#undef getstr +#endif +#ifdef getyx +inline void (getyx)(WINDOW* win, int& y, int& x) { getyx(win, y, x); } +#undef getyx +#endif +#ifdef inch +inline chtype (inch)() { return inch(); } +#undef inch +#endif +#ifdef insch +inline int (insch)(char c) { return insch(c); } +#undef insch +#endif +#ifdef insertln +inline int (insertln)() { return insertln(); } +#undef insertln +#endif +#ifdef leaveok +inline int (leaveok)(WINDOW* win, bool bf) { return leaveok(win, bf); } +#undef leaveok +#else +extern "C" int leaveok(WINDOW* win, bool bf); +#endif +#ifdef move +inline int (move)(int x, int y) { return move(x, y); } +#undef move +#endif +#ifdef refresh +inline int (rfresh)() { return refresh(); } +#undef refresh +#endif +#ifdef scrollok +inline int (scrollok)(WINDOW* win, bool bf) { return scrollok(win, bf); } +#undef scrollok +#else +#ifndef hpux +extern "C" int scrollok(WINDOW*, bool); +#else +extern "C" int scrollok(WINDOW*, char); +#endif +#endif +#ifdef standend +inline int (standend)() { return standend(); } +#undef standend +#endif +#ifdef standout +inline int (standout)() { return standout(); } +#undef standout +#endif +#ifdef wstandend +inline int (wstandend)(WINDOW *win) { return wstandend(win); } +#undef wstandend +#endif +#ifdef wstandout +inline int (wstandout)(WINDOW *win) { return wstandout(win); } +#undef wstandout +#endif +#ifdef winch +inline chtype (winch)(WINDOW* win) { return winch(win); } +#undef winch +#endif + +// deal with conflicting macros in ncurses.h which is SYSV based +#ifdef box +inline int _G_box(WINDOW* win, chtype v, chtype h) {return box(win, v, h); } +#undef box +inline int box(WINDOW* win, chtype v, chtype h) {return _G_box(win, v, h); } +#endif +#ifdef scroll +inline int (scroll)(WINDOW* win) { return scroll(win); } +#undef scroll +#endif +#ifdef touchwin +inline int (touchwin)(WINDOW* win) { return touchwin(win); } +#undef touchwin +#endif + +#ifdef mvwaddch +inline int (mvwaddch)(WINDOW *win, int y, int x, char ch) +{ return mvwaddch(win, y, x, ch); } +#undef mvwaddch +#endif +#ifdef mvwaddstr +inline int (mvwaddstr)(WINDOW *win, int y, int x, const char * str) +{ return mvwaddstr(win, y, x, (char*)str); } +#undef mvwaddstr +#endif +#ifdef mvwdelch +inline int (mvwdelch)(WINDOW *win, int y, int x) { return mvwdelch(win, y, x);} +#undef mvwdelch +#endif +#ifdef mvwgetch +inline int (mvwgetch)(WINDOW *win, int y, int x) { return mvwgetch(win, y, x);} +#undef mvwgetch +#endif +#ifdef mvwgetstr +inline int (mvwgetstr)(WINDOW *win, int y, int x, char *str) +{return mvwgetstr(win,y,x, str);} +#undef mvwgetstr +#endif +#ifdef mvwinch +inline chtype (mvwinch)(WINDOW *win, int y, int x) { return mvwinch(win, y, x);} +#undef mvwinch +#endif +#ifdef mvwinsch +inline int (mvwinsch)(WINDOW *win, int y, int x, char c) +{ return mvwinsch(win, y, x, c); } +#undef mvwinsch +#endif + +#ifdef mvaddch +inline int (mvaddch)(int y, int x, char ch) +{ return mvaddch(y, x, ch); } +#undef mvaddch +#endif +#ifdef mvaddstr +inline int (mvaddstr)(int y, int x, const char * str) +{ return mvaddstr(y, x, (char*)str); } +#undef mvaddstr +#endif +#ifdef mvdelch +inline int (mvdelch)(int y, int x) { return mvdelch(y, x);} +#undef mvdelch +#endif +#ifdef mvgetch +inline int (mvgetch)(int y, int x) { return mvgetch(y, x);} +#undef mvgetch +#endif +#ifdef mvgetstr +inline int (mvgetstr)(int y, int x, char *str) {return mvgetstr(y, x, str);} +#undef mvgetstr +#endif +#ifdef mvinch +inline chtype (mvinch)(int y, int x) { return mvinch(y, x);} +#undef mvinch +#endif +#ifdef mvinsch +inline int (mvinsch)(int y, int x, char c) +{ return mvinsch(y, x, c); } +#undef mvinsch +#endif + +extern int curses_initialized; + +// ------------------------------------------------------------------ + +#endif // __gcurses_h + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gkbdbase.cpp b/goldlib/gcui/gkbdbase.cpp new file mode 100644 index 0000000..e625b8f --- /dev/null +++ b/goldlib/gcui/gkbdbase.cpp @@ -0,0 +1,1836 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// Copyright (C) 2000 Jacobo Tarrio +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Keyboard functions. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include + +#include + +#if defined(__OS2__) +#define INCL_BASE +#include +#endif + +#ifdef __WIN32__ +#include +extern OSVERSIONINFO WinVer; +#endif + +#if defined(__UNIX__) && !defined(__USE_NCURSES__) +#include +#endif + +#if defined(__DJGPP__) +#include +#endif + +#if defined(__USE_NCURSES__) +#include +#endif + +#if defined(__linux__) +#include +#include +#endif + +#if defined(__BEOS__) +#include +#endif + +// ------------------------------------------------------------------ + +#if defined(__USE_NCURSES__) +int curses_initialized = 0; +#endif + + +// ------------------------------------------------------------------ + +#if defined(__WIN32__) +#define KBD_TEXTMODE (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT) +#endif + + +// ------------------------------------------------------------------ +// Global keyboard data + +#if defined(__WIN32__) && !defined(__USE_NCURSES__) +HANDLE gkbd_hin; +DWORD gkbd_kbdmode; +int gkbd_nt; +#endif + +GKbd gkbd; + +int blanked = false; + +bool right_alt_same_as_left = false; + +// ------------------------------------------------------------------ +// Keyboard Class Initializer + +void GKbd::Init() { + + #if defined(__USE_NCURSES__) + + // Both screen and keyboard must be initialized at once + if(0 == (curses_initialized++)) { + initscr(); + raw(); + noecho(); + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + } + + // WARNING: this might break with an old version of ncurses, or + // with another implementation of curses. I'm putting it here because + // it is quote useful most of the time :-) For other implementations of + // curses, you might have to compile curses yourself to achieve this. -jt + #if defined(NCURSES_VERSION) + if(not getenv("ESCDELAY")) // If not specified by user via environment, set + ESCDELAY = 50; // ms, slow for a 300bps terminal, fast for humans :-) + #endif + // For more ncurses-dependent code, look at the gkbd_curstable array + // and at the kbxget_raw() function -jt + + #elif defined(__OS2__) + + KBDINFO kbstInfo; + kbstInfo.cb = sizeof(kbstInfo); + KbdGetStatus(&kbstInfo, 0); + kbstInfo.fsMask = (USHORT)((kbstInfo.fsMask & 0xFFF7) | 0x0004); + KbdSetStatus(&kbstInfo, 0); + + #elif defined(__WIN32__) + + OSVERSIONINFO osversion; + osversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osversion); + gkbd_nt = make_bool(osversion.dwPlatformId & VER_PLATFORM_WIN32_NT); + gkbd_hin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + GetConsoleMode(gkbd_hin, &gkbd_kbdmode); + if(gkbd_kbdmode & KBD_TEXTMODE) + SetConsoleMode(gkbd_hin, gkbd_kbdmode & ~KBD_TEXTMODE); + + #elif defined(__UNIX__) + + gkbd_tty_init(); + + #endif +} + + +// ------------------------------------------------------------------ +// Keyboard Class constructor + +GKbd::GKbd() { + + kbuf = NULL; + onkey = NULL; + curronkey = NULL; + inmenu = 0; + source = 0; + polling = 0; + tickinterval = 0; + tickpress = tickvalue = gclock(); + tickfunc = NULL; + inidle = 0; + quitall = NO; + + // Detect enhanced keyboard by checking bit 4 at 0x00000496 + #if defined(__USE_NCURSES__) + extkbd = true; + #elif defined(__DJGPP__) + extkbd = _farpeekb (_dos_ds, 0x0496) & (1 << 4); + #elif defined(__MSDOS__) + extkbd = *((byte*)0x0496) & (1 << 4); + #elif defined(__OS2__) || defined(__WIN32__) + extkbd = true; + #endif + + Init(); + + #if defined(__UNIX__) && !defined(__USE_NCURSES__) && !defined(__BEOS__) + + gkbd_keymap_init(); + + char escseq[2]; + escseq[1] = NUL; + for(int n=0; n<256; n++) { + escseq[0] = (char)n; + if(n == 0x7F or n == 0x08) + gkbd_define_keysym(escseq, Key_BS); + else if(n == 0x09) + gkbd_define_keysym(escseq, Key_Tab); + else if(n == 0x0D) + gkbd_define_keysym(escseq, Key_Ent); + else + gkbd_define_keysym(escseq, (n < 128) ? (scancode_table[n]|n) : n); + } + + gkbd_define_keysym("^@", 0); + + gkbd_define_keysym("\033[A", Key_Up); + gkbd_define_keysym("\033[B", Key_Dwn); + gkbd_define_keysym("\033[C", Key_Rgt); + gkbd_define_keysym("\033[D", Key_Lft); + + gkbd_define_keysym("\033[[W", Key_C_Up); + gkbd_define_keysym("\033[[Z", Key_C_Dwn); + gkbd_define_keysym("\033[[Y", Key_C_Rgt); + gkbd_define_keysym("\033[[X", Key_C_Lft); + + gkbd_define_keysym("\033[1~", Key_Home); + gkbd_define_keysym("\033[7~", Key_Home); + gkbd_define_keysym("\033[H", Key_Home); + gkbd_define_keysym("\033[2~", Key_Ins); + gkbd_define_keysym("\033[3~", Key_Del); + gkbd_define_keysym("\033[4~", Key_End); + gkbd_define_keysym("\033[8~", Key_End); + gkbd_define_keysym("\033[F", Key_End); + gkbd_define_keysym("\033[5~", Key_PgUp); + gkbd_define_keysym("\033[6~", Key_PgDn); + + gkbd_define_keysym("\033[[A", Key_F1); + gkbd_define_keysym("\033[[B", Key_F2); + gkbd_define_keysym("\033[[C", Key_F3); + gkbd_define_keysym("\033[[D", Key_F4); + gkbd_define_keysym("\033[[E", Key_F5); + gkbd_define_keysym("\033[17~", Key_F6); + gkbd_define_keysym("\033[18~", Key_F7); + gkbd_define_keysym("\033[19~", Key_F8); + gkbd_define_keysym("\033[20~", Key_F9); + gkbd_define_keysym("\033[21~", Key_F10); + + gkbd_define_keysym("\033[23~", Key_S_F1); + gkbd_define_keysym("\033[24~", Key_S_F2); + gkbd_define_keysym("\033[25~", Key_S_F3); + gkbd_define_keysym("\033[26~", Key_S_F4); + gkbd_define_keysym("\033[28~", Key_S_F5); + gkbd_define_keysym("\033[29~", Key_S_F6); + gkbd_define_keysym("\033[31~", Key_S_F7); + gkbd_define_keysym("\033[32~", Key_S_F8); + gkbd_define_keysym("\033[33~", Key_S_F9); + gkbd_define_keysym("\033[34~", Key_S_F10); + + gkbd_define_keysym("\033""0", Key_A_0); + gkbd_define_keysym("\033""1", Key_A_1); + gkbd_define_keysym("\033""2", Key_A_2); + gkbd_define_keysym("\033""3", Key_A_3); + gkbd_define_keysym("\033""4", Key_A_4); + gkbd_define_keysym("\033""5", Key_A_5); + gkbd_define_keysym("\033""6", Key_A_6); + gkbd_define_keysym("\033""7", Key_A_7); + gkbd_define_keysym("\033""8", Key_A_8); + gkbd_define_keysym("\033""9", Key_A_9); + + gkbd_define_keysym("\033a", Key_A_A); + gkbd_define_keysym("\033b", Key_A_B); + gkbd_define_keysym("\033c", Key_A_C); + gkbd_define_keysym("\033d", Key_A_D); + gkbd_define_keysym("\033e", Key_A_E); + gkbd_define_keysym("\033f", Key_A_F); + gkbd_define_keysym("\033g", Key_A_G); + gkbd_define_keysym("\033h", Key_A_H); + gkbd_define_keysym("\033i", Key_A_I); + gkbd_define_keysym("\033j", Key_A_J); + gkbd_define_keysym("\033k", Key_A_K); + gkbd_define_keysym("\033l", Key_A_L); + gkbd_define_keysym("\033m", Key_A_M); + gkbd_define_keysym("\033n", Key_A_N); + gkbd_define_keysym("\033o", Key_A_O); + gkbd_define_keysym("\033p", Key_A_P); + gkbd_define_keysym("\033q", Key_A_Q); + gkbd_define_keysym("\033r", Key_A_R); + gkbd_define_keysym("\033s", Key_A_S); + gkbd_define_keysym("\033t", Key_A_T); + gkbd_define_keysym("\033u", Key_A_U); + gkbd_define_keysym("\033v", Key_A_V); + gkbd_define_keysym("\033w", Key_A_W); + gkbd_define_keysym("\033x", Key_A_X); + gkbd_define_keysym("\033y", Key_A_Y); + gkbd_define_keysym("\033z", Key_A_Z); + + gkbd_define_keysym("^?", Key_BS); + gkbd_define_keysym("\033\x7F", Key_A_BS); + gkbd_define_keysym("\033\x0D", Key_A_Ent); + gkbd_define_keysym("\033\x09", Key_A_Tab); + + #elif defined(__BEOS__) + + gkbd_keymap_init(); + + char escseq[2]; + escseq[1] = NUL; + for(int n=0; n<256; n++) { + escseq[0] = (char)n; + if(n == 0x08) + gkbd_define_keysym(escseq, Key_BS); + else if(n == 0x09) + gkbd_define_keysym(escseq, Key_Tab); + else if(n == 0x0D) + gkbd_define_keysym(escseq, Key_Ent); + else if(n == 0x7F) + gkbd_define_keysym(escseq, Key_Del); // ????? + else + gkbd_define_keysym(escseq, (n < 128) ? (scancode_table[n]|n) : n); + } + + // gkbd_define_keysym("^@", 0); ????????? + + gkbd_define_keysym("\033[A", Key_Up); + gkbd_define_keysym("\033[B", Key_Dwn); + gkbd_define_keysym("\033[C", Key_Rgt); + gkbd_define_keysym("\033[D", Key_Lft); + + gkbd_define_keysym("\033[1~", Key_Home); + gkbd_define_keysym("\033[2~", Key_Ins); + gkbd_define_keysym("\033[4~", Key_End); + gkbd_define_keysym("\033[5~", Key_PgUp); + gkbd_define_keysym("\033[6~", Key_PgDn); + + // gkbd_define_keysym("\033[3~", Key_Del); + + gkbd_define_keysym("\033[11~", Key_F1); + gkbd_define_keysym("\033[12~", Key_F2); + gkbd_define_keysym("\033[13~", Key_F3); + gkbd_define_keysym("\033[14~", Key_F4); + gkbd_define_keysym("\033[15~", Key_F5); + gkbd_define_keysym("\033[16~", Key_F6); + gkbd_define_keysym("\033[17~", Key_F7); + gkbd_define_keysym("\033[18~", Key_F8); + gkbd_define_keysym("\033[19~", Key_F9); + gkbd_define_keysym("\033[20~", Key_F10); + +/* + gkbd_define_keysym("\033\x7F", Key_A_BS); + gkbd_define_keysym("\033\x0D", Key_A_Ent); + gkbd_define_keysym("\033\x09", Key_A_Tab); +*/ + + #endif +} + + +// ------------------------------------------------------------------ +// Keyboard Class destructor + +GKbd::~GKbd() { + + #if defined(__USE_NCURSES__) + + if(0 == (--curses_initialized)) + endwin(); + + #elif defined(__WIN32__) + + if(gkbd_kbdmode & KBD_TEXTMODE) + SetConsoleMode(gkbd_hin, gkbd_kbdmode); + + #elif defined(__UNIX__) + + gkbd_keymap_reset(); + gkbd_tty_reset(); + + #endif +} + + +// ------------------------------------------------------------------ +// Local table for scancode() + +gkey scancode_table[] = { + + Key_C_2 & 0xFF00u, // 0x0300 C <2 @> [NUL] + Key_C_A & 0xFF00u, // 0x1E01 C [SOH] + Key_C_B & 0xFF00u, // 0x3002 C [STX] + Key_C_C & 0xFF00u, // 0x2E03 C [ETX] + Key_C_D & 0xFF00u, // 0x2004 C [EOT] + Key_C_E & 0xFF00u, // 0x1205 C [ENQ] + Key_C_F & 0xFF00u, // 0x2106 C [ACK] + Key_C_G & 0xFF00u, // 0x2207 C [BEL] + Key_C_H & 0xFF00u, // 0x2308 C [BS] + Key_C_I & 0xFF00u, // 0x1709 C [HT] + Key_C_J & 0xFF00u, // 0x240A C [LF] + Key_C_K & 0xFF00u, // 0x250B C [VT] + Key_C_L & 0xFF00u, // 0x260C C [FF] + Key_C_M & 0xFF00u, // 0x320D C [CR] + Key_C_N & 0xFF00u, // 0x310E C [SO] + Key_C_O & 0xFF00u, // 0x180F C [SI] + Key_C_P & 0xFF00u, // 0x1910 C

+ Key_S_Q & 0xFF00u, // 0x1051 + Key_S_R & 0xFF00u, // 0x1352 + Key_S_S & 0xFF00u, // 0x1F53 + Key_S_T & 0xFF00u, // 0x1454 + Key_S_U & 0xFF00u, // 0x1655 + Key_S_V & 0xFF00u, // 0x2F56 + Key_S_W & 0xFF00u, // 0x1157 + Key_S_X & 0xFF00u, // 0x2D58 + Key_S_Y & 0xFF00u, // 0x1559 + Key_S_Z & 0xFF00u, // 0x2C5A + Key_Lbr & 0xFF00u, // 0x1A5B <[> + Key_Bsl & 0xFF00u, // 0x2B5C <\> + Key_Rbr & 0xFF00u, // 0x1B5D <]> + Key_S_6 & 0xFF00u, // 0x075E <6 ^> + Key_S_Min & 0xFF00u, // 0x0C5F <- _> + Key_Grv & 0xFF00u, // 0x2960 <`> + Key_A & 0xFF00u, // 0x1E61 + Key_B & 0xFF00u, // 0x3062 + Key_C & 0xFF00u, // 0x2E63 + Key_D & 0xFF00u, // 0x2064 + Key_E & 0xFF00u, // 0x1265 + Key_F & 0xFF00u, // 0x2166 + Key_G & 0xFF00u, // 0x2267 + Key_H & 0xFF00u, // 0x2368 + Key_I & 0xFF00u, // 0x1769 + Key_J & 0xFF00u, // 0x246A + Key_K & 0xFF00u, // 0x256B + Key_L & 0xFF00u, // 0x266C + Key_M & 0xFF00u, // 0x326D + Key_N & 0xFF00u, // 0x316E + Key_O & 0xFF00u, // 0x186F + Key_P & 0xFF00u, // 0x1970

+ Key_Q & 0xFF00u, // 0x1071 + Key_R & 0xFF00u, // 0x1372 + Key_S & 0xFF00u, // 0x1F73 + Key_T & 0xFF00u, // 0x1474 + Key_U & 0xFF00u, // 0x1675 + Key_V & 0xFF00u, // 0x2F76 + Key_W & 0xFF00u, // 0x1177 + Key_X & 0xFF00u, // 0x2D78 + Key_Y & 0xFF00u, // 0x1579 + Key_Z & 0xFF00u, // 0x2C7A + Key_S_Lbr & 0xFF00u, // 0x1A7B <[ {> + Key_S_Bsl & 0xFF00u, // 0x2B7C <\ |> + Key_S_Rbr & 0xFF00u, // 0x1B7D <] }> + Key_S_Grv & 0xFF00u, // 0x297E <` ~> + Key_C_BS & 0xFF00u // 0x0E7F C [RUB] +}; + + +// ------------------------------------------------------------------ +// Returns the scan code of an ASCII character + +byte scancode(gkey ch) { + + if(KCodAsc(ch) <= 127) + return (byte)(scancode_table[KCodAsc(ch)] >> 8); + return 0; +} + + +// ------------------------------------------------------------------ +// Translate scancode for ASCII keys + +gkey keyscanxlat(gkey k) { + + // Only translate ASCII keys + if(KCodAsc(k)) { + + // Check for certain ctrl-keys + switch(KCodAsc(k)) { + + case 0x08: // CtrlH or BackSpace 23/0E + if(k == Key_BS) + return k; + else + break; + + case 0x09: // CtrlI or Tab 17/0F + if(k == Key_Tab) + return k; + else + break; + + case 0x0A: // CtrlJ or CtrlEnter or GreyCtrlEnter 24/1C/E0 + case 0x0D: // CtrlM or Enter or GreyEnter 32/1C/E0 + // First, translate Numpad-Enter to main Enter... + if(k == Key_EntG) + k = Key_Ent; + else if(k == Key_C_EntG) + k = Key_C_Ent; + else if(k == Key_A_EntG) + k = Key_A_Ent; + // ...and now return if main Enter + if((k == Key_Ent) or (k == Key_C_Ent) or (k == Key_A_Ent)) + return k; + else + break; + + case 0x1B: // Ctrl[ or Esc 1A/01 + if(k == Key_Esc) + return k; + else + break; + + // asa: Not sure that the following case is required: + // Key_S_3 == 0x0423, Key_C_U == 0x1615 + case 0x15: // CtrlU or Shift3 (on german keyboards) 16/04 + if(KCodScn(k) == 0x04) + return k; + break; + + case 0xE0: // Check for extended key and fix it if necessary + if(KCodScn(k)) { + KCodAsc(k) = 0x00; + return k; + } + break; + } + + // Translate scancode of ASCII key to a known value + if (KCodAsc(k) <= 127) + return (gkey)(scancode_table[KCodAsc(k)] | KCodAsc(k)); + else + return (gkey)(KCodAsc(k)); + } + + return k; +} + + +// ------------------------------------------------------------------ +// The following tables map curses keyboard codes to BIOS keyboard +// values. + +#if defined(__USE_NCURSES__) + +// This might not work with something other than ncurses... :-( +// If you ever port it to other curses implementation, remember +// that it might have to be changed to another data structure, or +// the array might have to be filled in another manner... + +int gkbd_curstable[] = { + Key_C_Brk, // KEY_BREAK + Key_Dwn, // KEY_DOWN + Key_Up, // KEY_UP + Key_Lft, // KEY_LEFT + Key_Rgt, // KEY_RIGHT + Key_Home, // KEY_HOME + Key_BS, // KEY_BACKSPACE + -1, // KEY_F0 + Key_F1, // KEY_F(1) + Key_F2, // KEY_F(2) + Key_F3, // KEY_F(3) + Key_F4, // KEY_F(4) + Key_F5, // KEY_F(5) + Key_F6, // KEY_F(6) + Key_F7, // KEY_F(7) + Key_F8, // KEY_F(8) + Key_F9, // KEY_F(9) + Key_F10, // KEY_F(10) + Key_F11, // KEY_F(11) + Key_F12, // KEY_F(12) + Key_S_F3, // KEY_F(13) + Key_S_F4, // KEY_F(14) + Key_S_F5, // KEY_F(15) + Key_S_F6, // KEY_F(16) + Key_S_F7, // KEY_F(17) + Key_S_F8, // KEY_F(18) + Key_S_F9, // KEY_F(19) + Key_S_F10, // KEY_F(20) + Key_S_F11, // KEY_F(21) + Key_S_F12, // KEY_F(22) + -1, // KEY_F(23) + -1, // KEY_F(24) + -1, // KEY_F(25) + -1, // KEY_F(26) + -1, // KEY_F(27) + -1, // KEY_F(28) + -1, // KEY_F(29) + -1, // KEY_F(30) + -1, // KEY_F(31) + -1, // KEY_F(32) + -1, // KEY_F(33) + -1, // KEY_F(34) + -1, // KEY_F(35) + -1, // KEY_F(36) + -1, // KEY_F(37) + -1, // KEY_F(38) + -1, // KEY_F(39) + -1, // KEY_F(40) + -1, // KEY_F(41) + -1, // KEY_F(42) + -1, // KEY_F(43) + -1, // KEY_F(44) + -1, // KEY_F(45) + -1, // KEY_F(46) + -1, // KEY_F(47) + -1, // KEY_F(48) + -1, // KEY_F(49) + -1, // KEY_F(50) + -1, // KEY_F(51) + -1, // KEY_F(52) + -1, // KEY_F(53) + -1, // KEY_F(54) + -1, // KEY_F(55) + -1, // KEY_F(56) + -1, // KEY_F(57) + -1, // KEY_F(58) + -1, // KEY_F(59) + -1, // KEY_F(60) + -1, // KEY_F(61) + -1, // KEY_F(62) + -1, // KEY_F(63) + -1, // KEY_DL + -1, // KEY_IL + Key_Del, // KEY_DC + Key_Ins, // KEY_IC + Key_Ins, // KEY_EIC + -1, // KEY_CLEAR + -1, // KEY_EOS + -1, // KEY_EOL + -1, // KEY_SF + -1, // KEY_SR + Key_PgDn, // KEY_NPAGE + Key_PgUp, // KEY_PPAGE + Key_Tab, // KEY_STAB + -1, // KEY_CTAB + -1, // KEY_CATAB + Key_Ent, // KEY_ENTER + -1, // KEY_SRESET + -1, // KEY_RESET + -1, // KEY_PRINT + Key_End, // KEY_LL (hmm... this should be lower left) + Key_Home, // KEY_A1 + Key_PgUp, // KEY_A3 + Key_5Num, // KEY_B2 + Key_End, // KEY_C1 + Key_PgDn, // KEY_C3 + Key_S_Tab, // KEY_BTAB + Key_Home, // KEY_BEG + -1, // KEY_CANCEL + -1, // KEY_CLOSE + -1, // KEY_COMMAND + -1, // KEY_COPY + -1, // KEY_CREATE + Key_End, // KEY_END + -1, // KEY_EXIT + -1, // KEY_FIND + -1, // KEY_HELP + -1, // KEY_MARK + -1, // KEY_MESSAGE + -1, // KEY_MOVE + -1, // KEY_NEXT + -1, // KEY_OPEN + -1, // KEY_OPTIONS + -1, // KEY_PREVIOUS + -1, // KEY_REDO + -1, // KEY_REFERENCE + -1, // KEY_REFRESH + -1, // KEY_REPLACE + -1, // KEY_RESTART + -1, // KEY_RESUME + -1, // KEY_SAVE + Key_S_Home,// KEY_SBEG + -1, // KEY_SCANCEL + -1, // KEY_SCOMMAND + -1, // KEY_SCOPY + -1, // KEY_SCREATE + Key_S_Del, // KEY_SDC + -1, // KEY_SDL + -1, // KEY_SELECT + Key_S_End, // KEY_SEND + -1, // KEY_SEOL + -1, // KEY_SEXIT + -1, // KEY_SFIND + -1, // KEY_SHELP + Key_S_Home,// KEY_SHOME + Key_S_Ins, // KEY_SIC + Key_S_Lft, // KEY_SLEFT + -1, // KEY_SMESSAGE + -1, // KEY_SMOVE + -1, // KEY_SNEXT + -1, // KEY_SOPTIONS + -1, // KEY_SPREVIOUS + -1, // KEY_SPRINT + -1, // KEY_SREDO + -1, // KEY_SREPLACE + Key_S_Rgt, // KEY_SRIGHT + -1, // KEY_SRSUME + -1, // KEY_SSAVE + -1, // KEY_SSUSPEND + -1, // KEY_SUNDO + -1, // KEY_SUSPEND + -1, // KEY_UNDO + -1, // KEY_MOUSE + -1 // KEY_RESIZE +}; + +int gkbd_cursgetch(int mode) { + + int key; +#ifndef BUGGY_NCURSES + nodelay(stdscr, mode); +#else + wtimeout(stdscr, mode ? 0 : -1); +#endif + key = getch(); +#ifndef BUGGY_NCURSES + nodelay(stdscr, FALSE); +#else + wtimeout(stdscr, -1); +#endif + + return key; +} + + +// ------------------------------------------------------------------ +// The following table maps NT virtual keycodes to PC BIOS keyboard +// values. For each virtual keycode there are four possible BIOS +// values: normal, shift, Ctrl, and ALT. Key combinations that have +// no BIOS equivalent have a value of -1, and are ignored. Extended +// (non-ASCII) key values have bit 8 set to 1 using the EXT macro. + +#elif defined(__WIN32__) + +#define EXT(key) ((key)|0x10000) +#define ISEXT(val) ((val)&0x10000) +#define EXTVAL(val) ((val)&0xFF) + +struct kbd { + int keycode; // virtual keycode + int normal; // BIOS keycode - normal + int shift; // BIOS keycode - Shift- + int ctrl; // BIOS keycode - Ctrl- + int alt; // BIOS keycode - Alt- +} __gkbd_nt2b_table [] = +{ + +// ------------------------------------------------------------------ +// Virtual key Normal Shift Control Alt + + { VK_BACK, Key_BS, Key_BS, Key_C_BS, Key_A_BS }, + { VK_TAB, Key_Tab, Key_S_Tab, Key_C_Tab, Key_A_Tab }, + { VK_RETURN, Key_Ent, Key_Ent, Key_C_Ent, Key_A_Ent }, + { VK_ESCAPE, Key_Esc, Key_Esc, Key_Esc, Key_A_Esc }, + { VK_SPACE, -1, -1, Key_Space, Key_Space }, + { VK_APPS, Key_S_F10, Key_S_F10, Key_S_F10, -1 }, + + { '0', Key_0, Key_S_0, -1, Key_A_0 }, + { '1', Key_1, Key_S_1, -1, Key_A_1 }, + { '2', Key_2, Key_S_2, Key_C_2, Key_A_2 }, + { '3', Key_3, Key_S_3, -1, Key_A_3 }, + { '4', Key_4, Key_S_4, -1, Key_A_4 }, + { '5', Key_5, Key_S_5, -1, Key_A_5 }, + { '6', Key_6, Key_S_6, Key_C_6, Key_A_6 }, + { '7', Key_7, Key_S_7, -1, Key_A_7 }, + { '8', Key_8, Key_S_8, -1, Key_A_8 }, + { '9', Key_9, Key_S_9, -1, Key_A_9 }, + { 'A', Key_A, Key_S_A, Key_C_A, Key_A_A }, + { 'B', Key_B, Key_S_B, Key_C_B, Key_A_B }, + { 'C', Key_C, Key_S_C, Key_C_C, Key_A_C }, + { 'D', Key_D, Key_S_D, Key_C_D, Key_A_D }, + { 'E', Key_E, Key_S_E, Key_C_E, Key_A_E }, + { 'F', Key_F, Key_S_F, Key_C_F, Key_A_F }, + { 'G', Key_G, Key_S_G, Key_C_G, Key_A_G }, + { 'H', Key_H, Key_S_H, Key_C_H, Key_A_H }, + { 'I', Key_I, Key_S_I, Key_C_I, Key_A_I }, + { 'J', Key_J, Key_S_J, Key_C_J, Key_A_J }, + { 'K', Key_K, Key_S_K, Key_C_K, Key_A_K }, + { 'L', Key_L, Key_S_L, Key_C_L, Key_A_L }, + { 'M', Key_M, Key_S_M, Key_C_M, Key_A_M }, + { 'N', Key_N, Key_S_N, Key_C_N, Key_A_N }, + { 'O', Key_O, Key_S_O, Key_C_O, Key_A_O }, + { 'P', Key_P, Key_S_P, Key_C_P, Key_A_P }, + { 'Q', Key_Q, Key_S_Q, Key_C_Q, Key_A_Q }, + { 'R', Key_R, Key_S_R, Key_C_R, Key_A_R }, + { 'S', Key_S, Key_S_S, Key_C_S, Key_A_S }, + { 'T', Key_T, Key_S_T, Key_C_T, Key_A_T }, + { 'U', Key_U, Key_S_U, Key_C_U, Key_A_U }, + { 'V', Key_V, Key_S_V, Key_C_V, Key_A_V }, + { 'W', Key_W, Key_S_W, Key_C_W, Key_A_W }, + { 'X', Key_X, Key_S_X, Key_C_X, Key_A_X }, + { 'Y', Key_Y, Key_S_Y, Key_C_Y, Key_A_Y }, + { 'Z', Key_Z, Key_S_Z, Key_C_Z, Key_A_Z }, + + { VK_PRIOR, Key_PgUp, Key_S_PgUp, Key_C_PgUp, Key_A_PgUp }, + { VK_NEXT, Key_PgDn, Key_S_PgDn, Key_C_PgDn, Key_A_PgDn }, + { VK_END, Key_End, Key_S_End, Key_C_End, Key_A_End }, + { VK_HOME, Key_Home, Key_S_Home, Key_C_Home, Key_A_Home }, + { VK_LEFT, Key_Lft, Key_S_Lft, Key_C_Lft, Key_A_Lft }, + { VK_UP, Key_Up, Key_S_Up, Key_C_Up, Key_A_Up }, + { VK_RIGHT, Key_Rgt, Key_S_Rgt, Key_C_Rgt, Key_A_Rgt }, + { VK_DOWN, Key_Dwn, Key_S_Dwn, Key_C_Dwn, Key_A_Dwn }, + { VK_INSERT, Key_Ins, Key_S_Ins, Key_C_Ins, Key_A_Ins }, + { VK_DELETE, Key_Del, Key_S_Del, Key_C_Del, Key_A_Del }, + { VK_CLEAR, Key_5Num, Key_S_5Num, Key_C_5Num, Key_A_5Num }, + { VK_NUMPAD0, Key_0, Key_S_Ins, Key_C_Ins, -1 }, + { VK_NUMPAD1, Key_1, Key_S_End, Key_C_End, -1 }, + { VK_NUMPAD2, Key_2, Key_S_Dwn, Key_C_Dwn, -1 }, + { VK_NUMPAD3, Key_3, Key_S_PgDn, Key_C_PgDn, -1 }, + { VK_NUMPAD4, Key_4, Key_S_Lft, Key_C_Lft, -1 }, + { VK_NUMPAD5, Key_5, Key_S_5Num, Key_C_5Num, -1 }, + { VK_NUMPAD6, Key_6, Key_S_Rgt, Key_C_Rgt, -1 }, + { VK_NUMPAD7, Key_7, Key_S_Home, Key_C_Home, -1 }, + { VK_NUMPAD8, Key_8, Key_S_Up, Key_C_Up, -1 }, + { VK_NUMPAD9, Key_9, Key_S_PgUp, Key_C_PgUp, -1 }, + { VK_MULTIPLY, Key_Multi, Key_Multi, Key_Multi, Key_Multi }, + { VK_ADD, Key_Plus, Key_Plus, Key_Plus, Key_Plus }, + { VK_SUBTRACT, Key_Minus, Key_Minus, Key_Minus, Key_Minus }, + { VK_DECIMAL, -1, -1, Key_C_Del, Key_A_Del }, + { VK_DIVIDE, Key_Sls, Key_Sls, Key_Sls, Key_Sls }, + { VK_F1, Key_F1, Key_S_F1, Key_C_F1, Key_A_F1 }, + { VK_F2, Key_F2, Key_S_F2, Key_C_F2, Key_A_F2 }, + { VK_F3, Key_F3, Key_S_F3, Key_C_F3, Key_A_F3 }, + { VK_F4, Key_F4, Key_S_F4, Key_C_F4, Key_A_F4 }, + { VK_F5, Key_F5, Key_S_F5, Key_C_F5, Key_A_F5 }, + { VK_F6, Key_F6, Key_S_F6, Key_C_F6, Key_A_F6 }, + { VK_F7, Key_F7, Key_S_F7, Key_C_F7, Key_A_F7 }, + { VK_F8, Key_F8, Key_S_F8, Key_C_F8, Key_A_F8 }, + { VK_F9, Key_F9, Key_S_F9, Key_C_F9, Key_A_F9 }, + { VK_F10, Key_F10, Key_S_F10, Key_C_F10, Key_A_F10 }, + { VK_F11, Key_F11, Key_S_F11, Key_C_F11, Key_A_F11 }, + { VK_F12, Key_F12, Key_S_F12, Key_C_F12, Key_A_F12 }, + + { -1, -1, -1, -1, -1 } // THE END +}; + + +// ------------------------------------------------------------------ + +bool is_oem_key(int keycode) +{ + switch(keycode) + { + // OEM specific keys + case 0x2a: + case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: + case 0xbf: case 0xc0: + case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: + case 0xe6: + case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: + case 0xef: case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: + return true; + + default: + return false; + } +} + + +// ------------------------------------------------------------------ + +int gkbd_nt2bios(INPUT_RECORD& inp) { + + int keycode = inp.Event.KeyEvent.wVirtualKeyCode; + int state = inp.Event.KeyEvent.dwControlKeyState; + int ascii = inp.Event.KeyEvent.uChar.AsciiChar; + + // Look up the virtual keycode in the table. Ignore unrecognized keys. + + kbd* k = &__gkbd_nt2b_table[0]; + while((keycode != k->keycode) and (k->keycode != -1)) + k++; + if(k->keycode == -1) { // value not in table + return ascii ? ascii : -1; + } + + // Check the state of the shift keys. ALT has highest + // priority, followed by Control, followed by Shift. + // Select the appropriate table entry based on shift state. + + int c; + if(state & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) + c = k->alt; + else if(state & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) + c = k->ctrl; + else if(state & SHIFT_PRESSED) + { + if (k->shift == -1) + c = ascii ? ascii : -1; + else + c = k->shift; + } + else { + // If it is a letter key, use the ASCII value supplied + // by NT to take into account the CapsLock state. + if (g_isupper(keycode) or (k->normal == -1)) + c = ascii ? ascii : -1; + else + c = k->normal; + } + + if (c != -1) + { + if (ascii and not (right_alt_same_as_left ? (state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) : (state & LEFT_ALT_PRESSED))) + if (isalnum(keycode)) + return (ascii == ' ') ? Key_Space : ascii; + if (ISEXT(c)) + return EXTVAL(c) << 8; + } + + return c; +} + +// ------------------------------------------------------------------ + +bool is_numpad_key(const INPUT_RECORD& inp) { + + if(not (inp.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY)) { + switch(inp.Event.KeyEvent.wVirtualKeyCode) { + case VK_CLEAR: + case VK_PRIOR: + case VK_NEXT: + case VK_END: + case VK_HOME: + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: + case VK_INSERT: + case VK_DELETE: + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + return true; + } + } + return false; +} + + +// ------------------------------------------------------------------ +// Numpad translation table + +#elif defined(__MSDOS__) || defined(__OS2__) + +const word numpad_keys[] = { + 0x4737, 0x4838, 0x4939, 0x0000, + 0x4B34, 0x0000, 0x4D36, 0x0000, + 0x4F31, 0x5032, 0x5133, + 0x5230, 0x532e +}; + +#endif + +#if defined(__linux__) +bool linux_cui_key(gkey k) { + switch(k) { + case Key_Dwn: + case Key_Up: + case Key_Lft: + case Key_Rgt: + case Key_Home: + case Key_Del: + case Key_Ins: + case Key_PgDn: + case Key_PgUp: + case Key_End: + return true; + } + return false; +} +#endif + +#if defined(__BEOS__) +int BeOSShiftState() +{ + int shift = 0; + uint32 mods = modifiers(); + if(mods&B_LEFT_SHIFT_KEY) shift |= LSHIFT; + if(mods&B_RIGHT_SHIFT_KEY) shift |= RSHIFT; + if(mods&B_CONTROL_KEY) shift |= GCTRL; + if(mods&B_OPTION_KEY) shift |= ALT; + return shift; +} +#endif + +// ------------------------------------------------------------------ +// Get key stroke + +gkey kbxget_raw(int mode) { +// mode - =0 - wait for key is pressed (returns code) +// =1 - test if keystroke is available (returns code if YES, +// otherwise returns 0) +// =2 - return Shifts key status + gkey k; + +// TO_PORT_TAG: kbxget_raw(3) + #if defined(__USE_NCURSES__) + + int key; + if(mode == 2) { + // We can't do much but we can at least this :-) + k = kbxget_raw(1); + key = 0; + switch(k) { + case Key_C_Brk: + key = GCTRL; + break; + case Key_S_Tab: + case Key_S_Home: + case Key_S_Del: + case Key_S_Ins: + case Key_S_Lft: + case Key_S_Rgt: + case Key_S_End: + key = LSHIFT; + break; + } + return key; + } + + // Get keystroke + key = gkbd_cursgetch(mode); + if(key == ERR) + return 0; + + // Prefix for Meta-key or Alt-key sequences + if(key == 27) { + int key2 = gkbd_cursgetch(TRUE); + // If no key follows, it is no Meta- or Alt- seq, but a single Esc + if(key2 == ERR) + k = Key_Esc; + // Compute the right keycode for the alt sequence + else if((key2 >= '1') and (key2 <= '9')) + k = 0x7800 + ((key2 - '1') << 8); + else if(key2 == '0') + k = 0x8100; + else if(g_isalpha(key2)) + k = (scancode_table[key2]); + else if(key2 == '\010') + k = Key_A_BS; + else if(key2 == '\011') + k = Key_A_Tab; + else if(key2 == '\015') + k = Key_A_Ent; + else { + // No correct Alt-sequence; ungetch last key and return Esc + if (mode != 1) + ungetch(key2); + k = Key_Esc; + } + + if((key2 != ERR) and (mode == 1)) + ungetch(key2); + } + // Curses sequence; lookup in nice table above + else if((key >= KEY_MIN) and (key <= KEY_MIN+sizeof(gkbd_curstable)/sizeof(int))) + k = (gkbd_curstable[key - KEY_MIN]); + else if(key == '\015') + k = Key_Ent; + else if(key == '\011') + k = Key_Tab; + else if(key == '\000') + k = Key_Space; + else + k = key; + + if(mode == 1) + ungetch(key); + + #elif defined(__MSDOS__) + + if(gkbd.extkbd) + mode |= 0x10; + + i86 cpu; + cpu.ah((byte)mode); + cpu.genint(0x16); + if(mode & 0x01) + if(cpu.flags() & 0x40) // if ZF is set, no key is available + return 0; + k = (gkey)cpu.ax(); + + if((mode & ~0x10) == 0) { + if((KCodAsc(k) == 0xE0) and (KCodScn(k) != 0)) { + if(kbxget_raw(2) & (LSHIFT | RSHIFT)) { + KCodAsc(k) = 0; + KCodScn(k) |= 0x80; + } + } + else + switch(KCodScn(k)) { + case 0x47: + case 0x48: + case 0x49: + case 0x4B: + case 0x4D: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + { + int shifts = kbxget_raw(2); + if(shifts & (LSHIFT | RSHIFT)) { + if(shifts & NUMLOCK) + KCodAsc(k) = 0; + else { + KCodAsc(k) = 0; + KCodScn(k) |= 0x80; + } + } + } + break; + default: + break; + } + } + + // If you test shift/alt/ctrl status with bios calls (e.g., using + // bioskey (2) or bioskey (0x12)) then you should also use bios calls + // for testing for keys. This can be done with by bioskey (1) or + // bioskey (0x11). Failing to do so can cause trouble in multitasking + // environments like DESQview/X. (Taken from DJGPP documentation) + if((mode & 0x02) == 1) + kbxget_raw(1); + + #elif defined(__OS2__) + + KBDKEYINFO kb; + mode &= 0xF; + if(mode == 0) + KbdCharIn(&kb, IO_WAIT, 0); + else if(mode == 2) { + KbdPeek(&kb, 0); + if(kb.fbStatus) + return (gkey)(kb.fsState & (RSHIFT|LSHIFT|GCTRL|ALT)); + else + return 0; + } + else { + KbdPeek(&kb, 0); + if(!(kb.fbStatus & 0x40)) + return 0; + } + KCodScn(k) = kb.chScan; + KCodAsc(k) = kb.chChar; + if(0x000 == KCodKey(k)) + return KEY_BRK; + if(0xE0 == KCodScn(k)) + KCodScn(k) = 0x1C; + else { + if(0xE0 == KCodAsc(k)) { + // If key on the alphanumeric part then don't touch it. + // This need to enter for example, russian 'p' char (code 0xe0) + if(KCodScn(k) >= 0x38) { + KCodAsc(k) = 0x00; + if(kb.fsState & (LSHIFT | RSHIFT)) + KCodScn(k) |= 0x80; + } + else + KCodScn(k) = 0x00; + } + else + switch(KCodScn(k)) { + case 0x47: + case 0x48: + case 0x49: + case 0x4B: + case 0x4D: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + if(kb.fsState & (LSHIFT | RSHIFT)) { + if(kb.fsState & NUMLOCK) + KCodAsc(k) = 0; + else { + KCodAsc(k) = 0; + KCodScn(k) |= 0x80; + } + } + break; + default: + break; + } + } + + #elif defined(__WIN32__) + + INPUT_RECORD inp; + DWORD nread; + static gkey KeyCtrlState = 0; + + if (mode == 3) { + return KeyCtrlState; + } + else if(mode == 2) { + return 0; + } + else if(mode & 0x01) { + + // Peek at next key + k = 0; + PeekConsoleInput(gkbd_hin, &inp, 1, &nread); + if(nread) { + if((inp.EventType == KEY_EVENT) and inp.Event.KeyEvent.bKeyDown) { + int kc = gkbd_nt2bios(inp); + if((kc != -1) or is_oem_key(inp.Event.KeyEvent.wVirtualKeyCode)) { + k = (gkey)kc; + return k; + } + } + + if ((inp.EventType != MOUSE_EVENT) || (WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT)) + { + // Discard other events + ReadConsoleInput(gkbd_hin, &inp, 1, &nread); + } + } + } + else { + + DWORD &CKS = inp.Event.KeyEvent.dwControlKeyState; + WORD &VKC = inp.Event.KeyEvent.wVirtualKeyCode; + char &ascii = inp.Event.KeyEvent.uChar.AsciiChar; + + while(1) { + + PeekConsoleInput(gkbd_hin, &inp, 1, &nread); + if(not nread) { + WaitForSingleObject(gkbd_hin, 1000); + continue; + } + + if((inp.EventType == KEY_EVENT) and inp.Event.KeyEvent.bKeyDown) { + bool alt_pressed = make_bool(CKS & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)); + bool ctrl_pressed = make_bool(CKS & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)); + bool shift_pressed = make_bool(CKS & SHIFT_PRESSED); + bool special_key = false; + + k = 0; + + if(alt_pressed) + special_key = is_numpad_key(inp); // Alt- + else if(not gkbd_nt and not (CKS & ENHANCED_KEY) and not (VKC == VK_CLEAR) and (ascii and not ctrl_pressed) and not (iscntrl(ascii) and shift_pressed)) + special_key = true; // It is alphanumeric key under Win9x + if(special_key) { + ReadConsole(gkbd_hin, &ascii, 1, &nread, NULL); + if(alt_pressed) { + k = (gkey)ascii; + break; + } + } + else { + ReadConsoleInput(gkbd_hin, &inp, 1, &nread); + } + + // Fix Win9x anomaly + if((CKS & NUMLOCK_ON) and not (CKS & ENHANCED_KEY) and (VKC == VK_DELETE)) + VKC = VK_DECIMAL; + + switch(VKC) { + // Not meanful keys + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + case VK_CAPITAL: + case VK_NUMLOCK: + case VK_SCROLL: + break; + + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + if(shift_pressed) { + WORD keytrans[10][2] = { + {VK_NUMPAD0, VK_INSERT}, + {VK_NUMPAD1, VK_END}, + {VK_NUMPAD2, VK_DOWN}, + {VK_NUMPAD3, VK_NEXT}, + {VK_NUMPAD4, VK_LEFT}, + {VK_NUMPAD5, VK_CLEAR}, + {VK_NUMPAD6, VK_RIGHT}, + {VK_NUMPAD7, VK_HOME}, + {VK_NUMPAD8, VK_UP}, + {VK_NUMPAD9, VK_PRIOR}, + }; + for(int i = 0; i < 10; i++) + if(VKC == keytrans[i][0]) { + VKC = keytrans[i][1]; + break; + } + } + // fall through + default: + { + int kc = gkbd_nt2bios(inp); + if(kc != -1) + k = (gkey)kc; + } + break; + } + if(k != 0) + break; + } + else { + // Discard other events + ReadConsoleInput(gkbd_hin, &inp, 1, &nread); + } + } + } + + #elif defined(__UNIX__) + + if(mode == 2) { + int key; + #if defined(__linux__) + // Under Linux we could use TIOCLINUX fn. 6 to read shift states on console + // Of course it is very unportable but should produce good results :-) + key = 6; + if(ioctl(fileno(stdin), TIOCLINUX, &key) == -1) + #endif + key = 0; + #ifdef __BEOS__ + key = BeOSShiftState(); + #endif + return key; + } + else if(mode & 0x01) { + + // Peek at next key + return gkbd_input_pending() ? 0xFFFF : 0; + } + else { + + k = gkbd_getmappedkey(); + } + + #endif + + #ifdef __linux__ + if(linux_cui_key(k)) { + // Under Linux we could use TIOCLINUX fn. 6 to read shift states on console + // Of course it is very unportable but should produce good results :-) + int shifts = 6; + if(ioctl(fileno(stdin), TIOCLINUX, &shifts) == -1) + shifts = 0; + if(shifts & (LSHIFT | RSHIFT)) + KCodScn(k) |= 0x80; + else if(shifts & GCTRL) { + switch(k) { + case Key_Ins: + k = Key_C_Ins; + break; + case Key_Del: + k = Key_C_Del; + break; + case Key_Dwn: + k = Key_C_Dwn; + break; + case Key_Up: + k = Key_C_Up; + break; + case Key_Lft: + k = Key_C_Lft; + break; + case Key_Rgt: + k = Key_C_Rgt; + break; + case Key_Home: + k = Key_C_Home; + break; + case Key_PgDn: + k = Key_C_PgDn; + break; + case Key_PgUp: + k = Key_C_PgUp; + break; + case Key_End: + k = Key_C_End; + break; + } + } + } else if(k == Key_BS) { + // Under Linux we could use TIOCLINUX fn. 6 to read shift states on console + // Of course it is very unportable but should produce good results :-) + int shifts = 6; + if(ioctl(fileno(stdin), TIOCLINUX, &shifts) == -1) + shifts = 0; + if(shifts & ALT) + k = Key_A_BS; + else if(shifts & GCTRL) + k = Key_C_BS; + } + #elif __BEOS__ + { + int shifts = BeOSShiftState(); + if(shifts & (ALT)) + switch(k){ + case Key_0: k=Key_A_0; break; + case Key_1: k=Key_A_1; break; + case Key_2: k=Key_A_2; break; + case Key_3: k=Key_A_3; break; + case Key_4: k=Key_A_4; break; + case Key_5: k=Key_A_5; break; + case Key_6: k=Key_A_6; break; + case Key_7: k=Key_A_7; break; + case Key_8: k=Key_A_8; break; + case Key_9: k=Key_A_9; break; + case Key_A: k=Key_A_A; break; + case Key_B: k=Key_A_B; break; + case Key_C: k=Key_A_C; break; + case Key_D: k=Key_A_D; break; + case Key_E: k=Key_A_E; break; + case Key_F: k=Key_A_F; break; + case Key_G: k=Key_A_G; break; + case Key_H: k=Key_A_H; break; + case Key_I: k=Key_A_I; break; + case Key_J: k=Key_A_J; break; + case Key_K: k=Key_A_K; break; + case Key_L: k=Key_A_L; break; + case Key_M: k=Key_A_M; break; + case Key_N: k=Key_A_N; break; + case Key_O: k=Key_A_O; break; + case Key_P: k=Key_A_P; break; + case Key_Q: k=Key_A_Q; break; + case Key_R: k=Key_A_R; break; + case Key_S: k=Key_A_S; break; + case Key_T: k=Key_A_T; break; + case Key_U: k=Key_A_U; break; + case Key_V: k=Key_A_V; break; + case Key_W: k=Key_A_W; break; + case Key_X: k=Key_A_X; break; + case Key_Y: k=Key_A_Y; break; + case Key_Z: k=Key_A_Z; break; + case Key_F1: k=Key_A_F1; break; + case Key_F2: k=Key_A_F2; break; + case Key_F3: k=Key_A_F3; break; + case Key_F4: k=Key_A_F4; break; + case Key_F5: k=Key_A_F5; break; + case Key_F6: k=Key_A_F6; break; + case Key_F7: k=Key_A_F7; break; + case Key_F8: k=Key_A_F8; break; + case Key_F9: k=Key_A_F9; break; + case Key_F10: k=Key_A_F10; break; + case Key_F11: k=Key_A_F11; break; + case Key_F12: k=Key_A_F12; break; + case Key_BS: k=Key_A_BS; break; + case Key_Ent: k=Key_A_Ent; break; + case Key_Tab: k=Key_A_Tab; break; + case Key_Dwn: k = Key_A_Dwn; break; + case Key_Up: k = Key_A_Up; break; + case Key_Lft: k = Key_A_Lft; break; + case Key_Rgt: k = Key_A_Rgt; break; + case Key_Home: k = Key_A_Home; break; + case Key_PgDn: k = Key_A_PgDn; break; + case Key_PgUp: k = Key_A_PgUp; break; + case Key_End: k = Key_A_End; break; + // case Key_: k=Key_A_; break; + default: break; + } + else if(shifts & (LSHIFT | RSHIFT)) + switch(k){ + case Key_F1: k=Key_S_F1; break; + case Key_F2: k=Key_S_F2; break; + case Key_F3: k=Key_S_F3; break; + case Key_F4: k=Key_S_F4; break; + case Key_F5: k=Key_S_F5; break; + case Key_F6: k=Key_S_F6; break; + case Key_F7: k=Key_S_F7; break; + case Key_F8: k=Key_S_F8; break; + case Key_F9: k=Key_S_F9; break; + case Key_F10: k=Key_S_F10; break; + case Key_F11: k=Key_S_F11; break; + case Key_F12: k=Key_S_F12; break; + case Key_Tab: k=Key_S_Tab; break; + default: KCodScn(k) |= 0x80; break; + } + else if(shifts & GCTRL) { + switch(k) { + case Key_Ent: k = Key_C_Ent; break; + case Key_Ins: k = Key_C_Ins; break; + case Key_Del: k = Key_C_Del; break; + case Key_Dwn: k = Key_C_Dwn; break; + case Key_Up: k = Key_C_Up; break; + case Key_Lft: k = Key_C_Lft; break; + case Key_Rgt: k = Key_C_Rgt; break; + case Key_Home: k = Key_C_Home; break; + case Key_PgDn: k = Key_C_PgDn; break; + case Key_PgUp: k = Key_C_PgUp; break; + case Key_End: k = Key_C_End; break; + case Key_BS: k = Key_C_BS; break; + case Key_F1: k=Key_C_F1; break; + case Key_F2: k=Key_C_F2; break; + case Key_F3: k=Key_C_F3; break; + case Key_F4: k=Key_C_F4; break; + case Key_F5: k=Key_C_F5; break; + case Key_F6: k=Key_C_F6; break; + case Key_F7: k=Key_C_F7; break; + case Key_F8: k=Key_C_F8; break; + case Key_F9: k=Key_C_F9; break; + case Key_F10: k=Key_C_F10; break; + case Key_F11: k=Key_C_F11; break; + case Key_F12: k=Key_C_F12; break; + } + } + } + #endif + +// TO_PORT_TAG: kbxget_raw(3) +#if defined(__WIN32__) + KeyCtrlState = (gkey)(inp.Event.KeyEvent.dwControlKeyState & 0xFFFF); +#endif + return k; +} + + +// ------------------------------------------------------------------ +// Get key stroke + +gkey kbxget(int mode) { + + return keyscanxlat(kbxget_raw(mode)); +} + + +// ------------------------------------------------------------------ +// Returns keycode of waiting key or zero if none + +gkey kbxhit() { + + return kbxget(0x01); +} + + +// ------------------------------------------------------------------ +// Clears internal keyboard buffer + +void kbclear() { + + while(gkbd.kbuf != NULL) { + + KBuf *kbuf = gkbd.kbuf->next; + throw_free(gkbd.kbuf); + gkbd.kbuf = kbuf; + } +} + + +// ------------------------------------------------------------------ +// Clear keyboard buffer + +void clearkeys() { + + while(kbxhit()) + kbxget(0x00); +} + + +// ------------------------------------------------------------------ +// Puts a keystroke into the CXL keyboard "buffer" + +bool gKeystacking = false; + +int kbput(gkey xch) +{ + if (gKeystacking) + { + if (gkbd.kbuf != NULL) + return -1; + + gKeystacking = false; + } + + KBuf* kbuf; + KBuf* temp; + + // allocate space for another keypress record + kbuf=(KBuf*)throw_malloc(sizeof(KBuf)); + + // find last record in linked list + if((temp=gkbd.kbuf)!=NULL) + for(;temp->next!=NULL;temp=temp->next); + + // add new record to end of linked list + kbuf->next=NULL; + kbuf->prev=temp; + if(temp != NULL) + temp->next=kbuf; + + // add keypress info to new record + kbuf->xch=xch; + + // if kbuf pointer was NULL, point it to new record + if(gkbd.kbuf == NULL) + gkbd.kbuf=kbuf; + + // return normally + return 0; +} + + +// ------------------------------------------------------------------ +// Put keys into the real keyboard buffer + +gkey kbput_(gkey xch) { + + #if defined(__MSDOS__) + + #if defined(__DJGPP__) + if(gkbd.extkbd) { + i86 cpu; + + cpu.ah(0x05); + cpu.cx((word)xch); + cpu.genint(0x16); + } + else { + #endif + + #define BufStart (word)peek(0x40,0x80) + #define BufEnd (word)peek(0x40,0x82) + #define BufHead (word)peek(0x40,0x1A) + #define BufTail (word)peek(0x40,0x1C) + #define BufTail_(a) poke(0x40,0x1C,(word)(a)) + + word OldBufTail; + + OldBufTail = BufTail; + if(BufTail == BufEnd-2) + BufTail_(BufStart); + else + BufTail_(BufTail+2); + + if(BufTail == BufHead) + BufTail_(OldBufTail); + else { + poke(0x40, OldBufTail, xch); + } + + #if defined(__DJGPP__) + } + #endif + + #endif + + return xch; +} + + +// ------------------------------------------------------------------ +// Put keys into the real keyboard buffer + +void kbputs_(char* str) { + + char* p; + + for(p=str; *p ;p++) + kbput_(gkey((scancode(*p)<<8)|*p)); +} + + +// ------------------------------------------------------------------ +// Change defined "on-key" list pointer + +KBnd* chgonkey(KBnd* list) { + + KBnd* temp; + + temp = gkbd.onkey; + gkbd.onkey = list; + + return temp; +} + + +// ------------------------------------------------------------------ +// Frees all active onkey definitions from memory + +void freonkey() { + + KBnd* temp; + + // free all onkey records in linked list + while(gkbd.onkey!=NULL) { + temp = gkbd.onkey->prev; + throw_free(gkbd.onkey); + gkbd.onkey = temp; + } +} + + +// ------------------------------------------------------------------ +// Attaches/detaches a key to a function + +int setonkey(gkey keycode, VfvCP func, gkey pass) { + + // search for a keycode that is already defined + KBnd* onkey = gkbd.onkey; + while(onkey) { + if(onkey->keycode == keycode) + break; + onkey = onkey->prev; + } + + // check to see if a key detachment is being requested + if(func == NULL) { + + // if no defined onkey was found, then error + if(onkey == NULL) + return 2; + + // delete record from linked list + KBnd* prev = onkey->prev; + KBnd* next = onkey->next; + if(prev) + prev->next = next; + if(next) + next->prev = prev; + if(onkey == gkbd.onkey) + gkbd.onkey = prev; + + // free memory allocated for deleted record + throw_free(onkey); + } + else { + + // if key was found, change func pointer + // otherwise create a new onkey record + if(onkey) + onkey->func = func; + else { + + // allocate memory for new record + onkey = (KBnd*)throw_malloc(sizeof(KBnd)); + if(onkey == NULL) + return 1; + + // add new record to linked list + if(gkbd.onkey) + gkbd.onkey->next = onkey; + onkey->prev = gkbd.onkey; + onkey->next = NULL; + gkbd.onkey = onkey; + + // save info in onkey record + gkbd.onkey->keycode = keycode; + gkbd.onkey->func = func; + gkbd.onkey->pass = pass; + } + } + + // return normally + return 0; +} + + +// ------------------------------------------------------------------ + +gkey key_tolower(gkey __keycode) { + + byte &ascii = KCodAsc(__keycode); + if(g_isupper(ascii)) + ascii = g_tolower(ascii); + return __keycode; +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gkbdbase.h b/goldlib/gcui/gkbdbase.h new file mode 100644 index 0000000..e2a8df9 --- /dev/null +++ b/goldlib/gcui/gkbdbase.h @@ -0,0 +1,168 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Keyboard functions (declarations). +// ------------------------------------------------------------------ + +#ifndef __gkbdbase_h +#define __gkbdbase_h + + +// ------------------------------------------------------------------ + +#include + + +// ------------------------------------------------------------------ +// Simple types + +typedef word gkey; + + +// ------------------------------------------------------------------ +// Keycode object + +inline gkey& KCodKey(gkey &key) { return key; } +inline byte& KCodAsc(gkey &key) { return *(((byte *)&key)+0); } +inline byte& KCodScn(gkey &key) { return *(((byte *)&key)+1); } + + +// ------------------------------------------------------------------ +// Definition of kbuf record + +struct KBuf { + KBuf* prev; // previous record + KBuf* next; // next record + gkey xch; // keypress +}; + + +// ------------------------------------------------------------------ +// Definition of onkey record + +struct KBnd { + KBnd* prev; // pointer to previous record + KBnd* next; // pointer to next record + gkey keycode; // Scan/ASCII code of trap key + VfvCP func; // address of onkey function + gkey pass; // key to pass back, 0=don't pass +}; + + +// ------------------------------------------------------------------ +// Definition of keyboard info record + +class GKbd { + +public: + + KBuf* kbuf; // Pointer to head record in key buffer + KBnd* onkey; // Pointer to head record in onkey list + KBnd* curronkey; // Pointer to current onkey record + int inmenu; // In-menu flag used by menuing functions + int source; // Source of keypress 0=kb, 1=kbuf, 2=mouse + int extkbd; // Extended keyboard 0=none, 1=yes + int polling; // Keyboard polling enabled + Clock tickinterval; // Minimum interval between ticks + Clock tickvalue; // Value from last tick + VfvCP tickfunc; // Function to call when a tick is generated + Clock tickpress; // Tick value at last keypress + bool inidle; // In-idle flag used by tickfunc + bool quitall; // Quit-all flag for menus etc. + + void Init(); + GKbd(); + ~GKbd(); +}; + +extern GKbd gkbd; + + +// ------------------------------------------------------------------ +// Keyboard status codes returned from kbstat() + +#define RSHIFT 1 // right shift pressed +#define LSHIFT 2 // left shift pressed +#define GCTRL 4 // [Ctrl] pressed +#define ALT 8 // [Alt] pressed +#define SCRLOCK 16 // [Scroll Lock] toggled +#define NUMLOCK 32 // [Num Lock] toggled +#define CAPSLOCK 64 // [Caps Lock] toggled +#define INS 128 // [Ins] toggled + + +// ------------------------------------------------------------------ + +extern gkey scancode_table[]; +extern bool right_alt_same_as_left; + + +// ------------------------------------------------------------------ +// Function prototypes + +KBnd* chgonkey (KBnd* kblist); +void clearkeys (); +void freonkey (); +int setonkey (gkey keycode, VfvCP func, gkey pass); +gkey getxch (int __tick=false); +void kbclear (); +gkey kbmhit (); +gkey kbxget (int mode=0); +gkey kbxhit (); +int kbput (gkey xch); +word kbput_ (gkey xch); +void kbputs_ (char* str); +byte scancode (gkey ch); +gkey waitkey (); +gkey waitkeyt (int duration); + +gkey key_tolower(gkey __keycode); + +gkey keyscanxlat(gkey k); + +gkey __kbxget(int __mode=0, long __ticks=0, VfvCP __idlefunc=NULL); + +void gkbdtickpressreset(); +void gkbdtickvaluereset(); + + +// ------------------------------------------------------------------ +// Inline functions + +inline gkey getxchtick() { return getxch(true); } +inline void kbdsettickfunc(VfvCP func) { gkbd.tickfunc = func; } + + +// ------------------------------------------------------------------ +// Shorthand definitions of keyboard scancodes + +#define KEY_BRK 0xFFFF // ^Break return from _KeyHit()/_KeyGet() + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gkbdcode.h b/goldlib/gcui/gkbdcode.h new file mode 100644 index 0000000..51520a7 --- /dev/null +++ b/goldlib/gcui/gkbdcode.h @@ -0,0 +1,466 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Define mnemonic symbols for full set of PC-Compatible non-display +// control and extended keycodes. +// ------------------------------------------------------------------ + +#ifndef __gkbdcode_h +#define __gkbdcode_h + + +// ------------------------------------------------------------------ +// Notes and Caveats (from the original TCXL 6.0 TCXLCOD.H file) +// +// 1. The keycode symbols suffixed with 'G' and marked in the 'G' +// column are the "Grey" keys around the numeric keypad or in a +// separate cursor-key cluster on "enhanced" keyboards. Those +// marked in the 'N' column are on numeric keypad. +// 2. The keycodes marked in the 'E' column are only available on +// "enhanced" 101/102-key keyboards with extended keyboard BIOS +// support enabled. The extended BIOS returns keycodes containing +// 0xE0 to distinguish duplicated keys, which are marked in the +// 'T' column. +// 3. If an "enhanced" keyboard and extended BIOS is detected, the +// DEFAULT is to enable extended BIOS support and translation of +// any duplicate extended keycodes. +// 4. Keycodes are ordered by character-code, then scan-code. +// 5. Control-Break, which has an actual keycode of 0x000 is +// returned as 0xFFFF. +// 6. The ASCII control-code names are shown in square brackets. +// 7. The Key_M_??? mouse-return codes are those returned by +// _MouGet(). +// ------------------------------------------------------------------ + +#include + + +// ------------------------------------------------------------------ + +#define Key_Lsr '<' +#define Key_Gtr '>' +#define Key_Multi '*' +#define Key_Plus '+' +#define Key_Minus '-' + + +// ------------------------------------------------------------------ + //- Normal key -------- N G E T - +#define Key_0 '0' // <0> - - - - +#define Key_1 '1' // <1> - - - - +#define Key_2 '2' // <2> - - - - +#define Key_3 '3' // <3> - - - - +#define Key_4 '4' // <4> - - - - +#define Key_5 '5' // <5> - - - - +#define Key_6 '6' // <6> - - - - +#define Key_7 '7' // <7> - - - - +#define Key_8 '8' // <8> - - - - +#define Key_9 '9' // <9> - - - - + +#define Key_A 0x1E61 // - - - - +#define Key_B 0x3062 // - - - - +#define Key_C 0x2E63 // - - - - +#define Key_D 0x2064 // - - - - +#define Key_E 0x1265 // - - - - +#define Key_F 0x2166 // - - - - +#define Key_G 0x2267 // - - - - +#define Key_H 0x2368 // - - - - +#define Key_I 0x1769 // - - - - +#define Key_J 0x246a // - - - - +#define Key_K 0x256b // - - - - +#define Key_L 0x266c // - - - - +#define Key_M 0x326d // - - - - +#define Key_N 0x316e // - - - - +#define Key_O 0x186f // - - - - +#define Key_P 0x1970 //

- - - - +#define Key_Q 0x1071 // - - - - +#define Key_R 0x1372 // - - - - +#define Key_S 0x1F73 // - - - - +#define Key_T 0x1474 // - - - - +#define Key_U 0x1675 // - - - - +#define Key_V 0x2F76 // - - - - +#define Key_W 0x1177 // - - - - +#define Key_X 0x2D78 // - - - - +#define Key_Y 0x1579 // - - - - +#define Key_Z 0x2C7A // - - - - +#define Key_StrG 0x372A // <*> - G - - +#define Key_PlsG 0x4E2B // <+> - G - - +#define Key_Com 0x332C // <,> - - - - +#define Key_MinG 0x4A2D // <-> - G - - +#define Key_Dot 0x342E // <.> - - - - +#define Key_BS 0x0E08 // - - - - +#define Key_5Num 0x4C00 // N - E - +#define Key_Del 0x5300 // N - - - +#define Key_DelG 0x53E0 // Grey - G E T +#define Key_Dwn 0x5000 // N - - - +#define Key_DwnG 0x50E0 // Grey - G E T +#define Key_End 0x4F00 // N - - - +#define Key_EndG 0x4FE0 // Grey - G E T +#define Key_Ent 0x1C0D // - - - - +#define Key_EntG 0xE00D // Grey - G E T +#define Key_Esc 0x011B // - - - - +#define Key_F1 0x3B00 // - - - - +#define Key_F2 0x3C00 // - - - - +#define Key_F3 0x3D00 // - - - - +#define Key_F4 0x3E00 // - - - - +#define Key_F5 0x3F00 // - - - - +#define Key_F6 0x4000 // - - - - +#define Key_F7 0x4100 // - - - - +#define Key_F8 0x4200 // - - - - +#define Key_F9 0x4300 // - - - - +#define Key_F10 0x4400 // - - - - +#define Key_F11 0x8500 // - - E - +#define Key_F12 0x8600 // - - E - +#define Key_Home 0x4700 // N - - - +#define Key_HomeG 0x47E0 // Grey - G E T +#define Key_Ins 0x5200 // N - - - +#define Key_InsG 0x52E0 // Grey - G E T +#define Key_Lft 0x4B00 // N - - - +#define Key_LftG 0x4BE0 // Grey - G E T +#define Key_PgDn 0x5100 // N - - - +#define Key_PgDnG 0x51E0 // Grey - G E T +#define Key_PgUp 0x4900 // N - - - +#define Key_PgUpG 0x49E0 // Grey - G E T +#define Key_Rgt 0x4D00 // N - - - +#define Key_RgtG 0x4DE0 // Grey - G E T +#define Key_Space 0x3920 // - - - - +#define Key_Tab 0x0F09 // - - - - +#define Key_Up 0x4800 // N - - - +#define Key_UpG 0x48E0 // Grey - G E T +#define Key_Quo 0x2827 // <'> - - - - +#define Key_Min 0x0C2D // <-> - - - - +#define Key_Sls 0x352F // - - - - +#define Key_Smi 0x273B // <;> - - - - +#define Key_Equ 0x0D3D // <=> - - - - +#define Key_Lbr 0x1A5B // <[> - - - - +#define Key_Bsl 0x2B5C // <\> - - - - +#define Key_Rbr 0x1B5D // <]> - - - - +#define Key_Grv 0x2960 // <`> - - - - + +// ------------------------------------------------------------------ + //- Shift key --------- N G E T - +#define Key_S_0 0x0B29 // <0 )> - - - - +#define Key_S_1 0x0221 // <1 !> - - - - +#define Key_S_2 0x0340 // <2 @> - - - - +#define Key_S_3 0x0423 // <3 #> - - - - +#define Key_S_4 0x0524 // <4 $> - - - - +#define Key_S_5 0x0625 // <5 %> - - - - +#define Key_S_6 0x075E // <6 ^> - - - - +#define Key_S_7 0x0826 // <7 &> - - - - +#define Key_S_8 0x092A // <8 *> - - - - +#define Key_S_9 0x0A28 // <9 (> - - - - +#define Key_S_A 0x1E41 // - - - - +#define Key_S_B 0x3042 // - - - - +#define Key_S_C 0x2E43 // - - - - +#define Key_S_D 0x2044 // - - - - +#define Key_S_E 0x1245 // - - - - +#define Key_S_F 0x2146 // - - - - +#define Key_S_G 0x2247 // - - - - +#define Key_S_H 0x2348 // - - - - +#define Key_S_I 0x1749 // - - - - +#define Key_S_J 0x244a // - - - - +#define Key_S_K 0x254b // - - - - +#define Key_S_L 0x264c // - - - - +#define Key_S_M 0x324d // - - - - +#define Key_S_N 0x314e // - - - - +#define Key_S_O 0x184f // - - - - +#define Key_S_P 0x1950 //

- - - - +#define Key_S_Q 0x1051 // - - - - +#define Key_S_R 0x1352 // - - - - +#define Key_S_S 0x1F53 // - - - - +#define Key_S_T 0x1454 // - - - - +#define Key_S_U 0x1655 // - - - - +#define Key_S_V 0x2F56 // - - - - +#define Key_S_W 0x1157 // - - - - +#define Key_S_X 0x2D58 // - - - - +#define Key_S_Y 0x1559 // - - - - +#define Key_S_Z 0x2C5a // - - - - +#define Key_S_Quo 0x2822 // <' "> - - - - +#define Key_S_Com 0x333C // <, >> - - - - +#define Key_S_Min 0x0C5F // <- _> - - - - +#define Key_S_Dot 0x343E // <. <> - - - - +#define Key_S_Sls 0x353F // - - - - +#define Key_S_Smi 0x273A // <; :> - - - - +#define Key_S_Equ 0x0D2B // <= +> - - - - +#define Key_S_Lbr 0x1A7B // <[ {> - - - - +#define Key_S_Bsl 0x2B7C // <\ |> - - - - +#define Key_S_Rbr 0x1B7D // <] }> - - - - +#define Key_S_Grv 0x297E // <` ~> - - - - +#define Key_S_5Num 0x4C35 // S N - - - +#define Key_S_F1 0x5400 // S - - - - +#define Key_S_F2 0x5500 // S - - - - +#define Key_S_F3 0x5600 // S - - - - +#define Key_S_F4 0x5700 // S - - - - +#define Key_S_F5 0x5800 // S - - - - +#define Key_S_F6 0x5900 // S - - - - +#define Key_S_F7 0x5A00 // S - - - - +#define Key_S_F8 0x5B00 // S - - - - +#define Key_S_F9 0x5C00 // S - - - - +#define Key_S_F10 0x5D00 // S - - - - +#define Key_S_F11 0x8700 // S - - E - +#define Key_S_F12 0x8800 // S - - E - +#define Key_S_Tab 0x0F00 // S - - - - +#if !defined(__UNIX__) || defined(__USE_NCURSES__) +#define Key_S_Ins 0xD200 // S Grey - G E T +#define Key_S_Lft 0xCB00 // S Grey - G E T +#define Key_S_PgDn 0xD100 // S Grey - G E T +#define Key_S_PgUp 0xC900 // S Grey - G E T +#define Key_S_Rgt 0xCD00 // S Grey - G E T +#define Key_S_Up 0xC800 // S Grey - G E T +#define Key_S_Dwn 0xD000 // S Grey - G E T +#define Key_S_End 0xCF00 // S Grey - G E T +#define Key_S_Home 0xC700 // S Grey - G E T +#define Key_S_Del 0xD300 // S N - - - +#else +#define Key_S_Home 0x4737 // S N - - - +#define Key_S_HomeG 0x47E0 // S Grey - G E T +#define Key_S_Ins 0x5230 // S N - - - +#define Key_S_InsG 0x52E0 // S Grey - G E T +#define Key_S_Lft 0x4B34 // S N - - - +#define Key_S_LftG 0x4BE0 // S Grey - G E T +#define Key_S_PgDn 0x5133 // S N - - - +#define Key_S_PgDnG 0x51E0 // S Grey - G E T +#define Key_S_PgUp 0x4939 // S N - - - +#define Key_S_PgUpG 0x49E0 // S Grey - G E T +#define Key_S_Rgt 0x4D36 // S N - - - +#define Key_S_RgtG 0x4DE0 // S Grey - G E T +#define Key_S_Up 0x4838 // S N - - - +#define Key_S_UpG 0x48E0 // S Grey - G E T +#define Key_S_Dwn 0x5032 // S N - - - +#define Key_S_DwnG 0x50E0 // S Grey - G E T +#define Key_S_End 0x4F31 // S N - - - +#define Key_S_EndG 0x4FE0 // S Grey - G E T +#define Key_S_Del 0x532E // S N - - - +#define Key_S_DelG 0x53E0 // S Grey - G E T +#endif + +// ------------------------------------------------------------------ + //- Control key ------- N G E T - +#define Key_C_2 0x0300 // C <2 @> [NUL] - - - - +#define Key_C_A 0x1E01 // C [SOH] - - - - +#define Key_C_B 0x3002 // C [STX] - - - - +#define Key_C_C 0x2E03 // C [ETX] - - - - +#define Key_C_D 0x2004 // C [EOT] - - - - +#define Key_C_E 0x1205 // C [ENQ] - - - - +#define Key_C_F 0x2106 // C [ACK] - - - - +#define Key_C_G 0x2207 // C [BEL] - - - - +#define Key_C_H 0x2308 // C [BS] - - - - +#define Key_C_I 0x1709 // C [HT] - - - - +#define Key_C_J 0x240A // C [LF] - - - - +#define Key_C_K 0x250B // C [VT] - - - - +#define Key_C_L 0x260C // C [FF] - - - - +#define Key_C_M 0x320D // C [CR] - - - - +#define Key_C_N 0x310E // C [SO] - - - - +#define Key_C_O 0x180F // C [SI] - - - - +#define Key_C_P 0x1910 // C

[DLE] - - - - +#define Key_C_Q 0x1011 // C [DC1] - - - - +#define Key_C_R 0x1312 // C [DC2] - - - - +#define Key_C_S 0x1F13 // C [DC3] - - - - +#define Key_C_T 0x1414 // C [DC4] - - - - +#define Key_C_U 0x1615 // C [NAK] - - - - +#define Key_C_V 0x2F16 // C [SYN] - - - - +#define Key_C_W 0x1117 // C [ETB] - - - - +#define Key_C_X 0x2D18 // C [CAN] - - - - +#define Key_C_Y 0x1519 // C [EM] - - - - +#define Key_C_Z 0x2C1A // C [SUB] - - - - +#define Key_C_StrG 0x7200 // C <*> Grey - G E - +#define Key_C_PlsG 0x9000 // C <+> Grey - G E - +#define Key_C_Min 0x0C1F // C <- _> - - - - +#define Key_C_MinG 0x8E00 // C <-> Grey - G E - +#define Key_C_6 0x071E // C <7 &> [RS] - - - - +#define Key_C_Brk 0xFFFF // C Grey - - - - +#define Key_C_BS 0x0E7F // C [RUB] - - - - +#define Key_C_5Num 0x8F00 // C N - E - +#define Key_C_Del 0x9300 // C - - E - +#define Key_C_DelG 0x93E0 // C Grey - G E T +#define Key_C_Dwn 0x9100 // C - - E - +#define Key_C_DwnG 0x91E0 // C Grey - G E T +#define Key_C_End 0x7500 // C N - - - +#define Key_C_EndG 0x75E0 // C Grey - G E T +#define Key_C_EntG 0xE00A // C Grey - G E T +#define Key_C_Ent 0x1C0A // C [LF] - - - - +#define Key_C_F1 0x5E00 // C - - - - +#define Key_C_F2 0x5F00 // C - - - - +#define Key_C_F3 0x6000 // C - - - - +#define Key_C_F4 0x6100 // C - - - - +#define Key_C_F5 0x6200 // C - - - - +#define Key_C_F6 0x6300 // C - - - - +#define Key_C_F7 0x6400 // C - - - - +#define Key_C_F8 0x6500 // C - - - - +#define Key_C_F9 0x6600 // C - - - - +#define Key_C_F10 0x6700 // C - - - - +#define Key_C_F11 0x8900 // C - - E - +#define Key_C_F12 0x8A00 // C - - E - +#define Key_C_Home 0x7700 // C N - - - +#define Key_C_HomeG 0x77E0 // C Grey - G E T +#define Key_C_Ins 0x9200 // C - - E - +#define Key_C_InsG 0x92E0 // C Grey - G E T +#define Key_C_Lft 0x7300 // C N - - - +#define Key_C_LftG 0x73E0 // C Grey - G E T +#define Key_C_PgDn 0x7600 // C N - - - +#define Key_C_PgDnG 0x76E0 // C Grey - G E T +#define Key_C_PgUp 0x8400 // C N - - - +#define Key_C_PgUpG 0x84E0 // C Grey - G E T +#define Key_C_Rgt 0x7400 // C N - - - +#define Key_C_RgtG 0x74E0 // C Grey - G E T +#define Key_C_Tab 0x9400 // C - - E - +#define Key_C_Up 0x8D00 // C - - E - +#define Key_C_UpG 0x8DE0 // C Grey - G E T +#define Key_C_Lbr 0x1A1B // C <[ {> [ESC] - - - - +#define Key_C_Bsl 0x2B1C // C <\ |> [FS] - - - - +#define Key_C_Rbr 0x1B1D // C <] }> [GS] - - - - + +// ------------------------------------------------------------------ + //- Alt key ----------- N G E T - +#define Key_A_0 0x8100 // A <0 )> - - - - +#define Key_A_1 0x7800 // A <1 !> - - - - +#define Key_A_2 0x7900 // A <2 @> - - - - +#define Key_A_3 0x7A00 // A <3 #> - - - - +#define Key_A_4 0x7B00 // A <4 ^> - - - - +#define Key_A_5 0x7C00 // A <5 %> - - - - +#define Key_A_6 0x7D00 // A <6 %> - - - - +#define Key_A_7 0x7E00 // A <7 &> - - - - +#define Key_A_8 0x7F00 // A <8 *> - - - - +#define Key_A_9 0x8000 // A <9 (> - - - - +#define Key_A_A 0x1E00 // A - - - - +#define Key_A_B 0x3000 // A - - - - +#define Key_A_C 0x2E00 // A - - - - +#define Key_A_D 0x2000 // A - - - - +#define Key_A_E 0x1200 // A - - - - +#define Key_A_F 0x2100 // A - - - - +#define Key_A_G 0x2200 // A - - - - +#define Key_A_H 0x2300 // A - - - - +#define Key_A_I 0x1700 // A - - - - +#define Key_A_J 0x2400 // A - - - - +#define Key_A_K 0x2500 // A - - - - +#define Key_A_L 0x2600 // A - - - - +#define Key_A_M 0x3200 // A - - - - +#define Key_A_N 0x3100 // A - - - - +#define Key_A_O 0x1800 // A - - - - +#define Key_A_P 0x1900 // A

- - - - +#define Key_A_Q 0x1000 // A - - - - +#define Key_A_R 0x1300 // A - - - - +#define Key_A_S 0x1F00 // A - - - - +#define Key_A_T 0x1400 // A - - - - +#define Key_A_U 0x1600 // A - - - - +#define Key_A_V 0x2F00 // A - - - - +#define Key_A_W 0x1100 // A - - - - +#define Key_A_X 0x2D00 // A - - - - +#define Key_A_Y 0x1500 // A - - - - +#define Key_A_Z 0x2C00 // A - - - - +#define Key_A_Quo 0x2800 // A <' "> - - E - +#define Key_A_PlsG 0x4E00 // A <+> Grey - G E - +#define Key_A_Com 0x3300 // A <, <> - - E - +#define Key_A_Min 0x8200 // A <- _> - - - - +#define Key_A_MinG 0x4A00 // A <-> Grey - G E - +#define Key_A_Dot 0x3400 // A <. >> - - E - +#define Key_A_Sls 0x3500 // A - - E - +#define Key_A_Smi 0x2700 // A <; :> - - E - +#define Key_A_Equ 0x8300 // A <= +> - - - - +#define Key_A_BS 0x0E00 // A - - E - +#define Key_A_5Num 0x4C00 // A N - E - +#define Key_A_Del 0xA300 // A - - E - +#define Key_A_DelG 0xA300 // A Grey - G E - +#define Key_A_Dwn 0xA000 // A - - E - +#define Key_A_DwnG 0xA000 // A Grey - G E - +#define Key_A_End 0x9F00 // A - - E - +#define Key_A_EndG 0x9F00 // A Grey - G E - +#define Key_A_EntG 0xA600 // A - - E - +#define Key_A_Esc 0x0100 // A - - E - +#define Key_A_F1 0x6800 // A - - - - +#define Key_A_F2 0x6900 // A - - - - +#define Key_A_F3 0x6A00 // A - - - - +#define Key_A_F4 0x6B00 // A - - - - +#define Key_A_F5 0x6C00 // A - - - - +#define Key_A_F6 0x6D00 // A - - - - +#define Key_A_F7 0x6E00 // A - - - - +#define Key_A_F8 0x6F00 // A - - - - +#define Key_A_F9 0x7000 // A - - - - +#define Key_A_F10 0x7100 // A - - - - +#define Key_A_F11 0x8B00 // A - - E - +#define Key_A_F12 0x8C00 // A - - E - +#define Key_A_Home 0x9700 // A - - E - +#define Key_A_HomeG 0x9700 // A Grey - G E - +#define Key_A_Ins 0xA200 // A - - E - +#define Key_A_InsG 0xA200 // A Grey - G E - +#define Key_A_Lft 0x9B00 // A - - E - +#define Key_A_LftG 0x9B00 // A Grey - G E - +#define Key_A_PgDn 0xA100 // A - - E - +#define Key_A_PgDnG 0xA100 // A Grey - G E - +#define Key_A_PgUp 0x9900 // A - - E - +#define Key_A_PgUpG 0x9900 // A Grey - G E - +#define Key_A_Rgt 0x9D00 // A - - E - +#define Key_A_Up 0x9800 // A - - E - +#define Key_A_UpG 0x9800 // A Grey - G E - +#define Key_A_Lbr 0x1A00 // A <[ {> - - E - +#define Key_A_Bsl 0x2B00 // A <\ |> - - E - +#define Key_A_Rbr 0x1B00 // A <] }> - - E - +#define Key_A_Grv 0x2900 // A <` ~> - - E - + +// ------------------------------------------------------------------ + //- Mouse KeyCode Returns ------- +#define Key_M_Scn 0xD4 // Scan-code +#define Key_M_Clk 0x30 // Single-click keycodes +#define Key_M_ClkL 0xD431 // Left-button +#define Key_M_ClkR 0xD432 // Right-button +#define Key_M_ClkM 0xD434 // Middle-button + +#define Key_M_DClk 0x20 // Double-click keycodes +#define Key_M_DClkL 0xD421 // Left-button +#define Key_M_DClkR 0xD422 // Right-button +#define Key_M_DClkM 0xD424 // Middle-button + +#define Key_M_Prs 0x30 // Single-press keycodes +#define Key_M_PrsL 0xD431 // Left-button +#define Key_M_PrsR 0xD432 // Right-button +#define Key_M_PrsM 0xD434 // Middle-button +#define Key_M_Rel 0x40 // Single-release keycodes +#define Key_M_RelL 0xD441 // Left-button +#define Key_M_RelR 0xD442 // Right-button +#define Key_M_RelM 0xD444 // Middle-button + +#define Key_M_Mov 0x50 // Mouse motion keycodes +#define Key_M_Up 0xD450 // Motion [Up] +#define Key_M_Dwn 0xD451 // Motion [Down] +#define Key_M_Lft 0xD452 // Motion [Left] +#define Key_M_Rgt 0xD453 // Motion [Right] + + +// ------------------------------------------------------------------ +// Goldware internal keycodes + +#define Key_Tick 0x0200 // Timer tick +#define Key_Auto 0xFD00 // Auto macro +#define Key_Macro 0xFE00 // Macro + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gkbdgetm.cpp b/goldlib/gcui/gkbdgetm.cpp new file mode 100644 index 0000000..9d53d56 --- /dev/null +++ b/goldlib/gcui/gkbdgetm.cpp @@ -0,0 +1,330 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Keyboard functions. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#ifdef GOLD_MOUSE +#include +#endif + + +// ------------------------------------------------------------------ +// Event sources + +const int GEVT_KEYBOARD = 0; +const int GEVT_BUFFER = 1; +const int GEVT_MOUSE = 2; +const int GEVT_TICK = 3; + + +// ------------------------------------------------------------------ + +void gkbdtickpressreset() { + + gkbd.tickpress = gclock(); +} + + +// ------------------------------------------------------------------ + +void gkbdtickvaluereset() { + + gkbd.tickvalue = gclock(); +} + + +// ------------------------------------------------------------------ + +gkey kbmhit() { + + gkey k; + + // Check for keypress in internal buffer or keyboard + if(gkbd.kbuf) { + gkbd.source = GEVT_BUFFER; + k = gkbd.kbuf->xch; + } + else { + gkbd.source = GEVT_KEYBOARD; + k = kbxhit(); + } + + return k; +} + + +// ------------------------------------------------------------------ + +static void kbd_call_func(VfvCP func) { + + int row, col; + bool hidden = vcurhidden(); + vposget(&row,&col); + _menu_t* menu = gwin.cmenu; + (*func)(); + gwin.cmenu = menu; + vposset(row,col); + if(hidden) + vcurhide(); + else + vcurshow(); +} + + +// ------------------------------------------------------------------ + +static _item_t* find_hotkey(_menu_t* wmenu, gkey xch) { + + _item_t* witem; + _item_t* item; + + // do while more items in this menu + for(witem=wmenu->item; witem!=NULL; witem=witem->prev) { + + // if hot key matches keypress, return its item address + if(witem->hotkey==xch and (!(witem->fmask&M_NOSEL)) and witem->select!=NULL) + return witem; + + // if current item has a child menu, process it + if(witem->child!=NULL) { + item = find_hotkey((_menu_t*)witem->child, xch); + if(item!=NULL) + return item; + } + } + + // return address of item found + return witem; +} + + +// ------------------------------------------------------------------ + +static void makeextkey(gkey xshift, gkey& xkey) { + + switch(xkey) { + case Key_Home: + case Key_C_Home: + if(xshift & ALT) + xkey = Key_A_HomeG; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_End: + case Key_C_End: + if(xshift & ALT) + xkey = Key_A_EndG; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_Up: + if(xshift & ALT) + xkey = Key_A_UpG; + else if(xshift & GCTRL) + xkey = Key_C_Up; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_Dwn: + if(xshift & ALT) + xkey = Key_A_DwnG; + else if(xshift & GCTRL) + xkey = Key_C_Dwn; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_Lft: + if(xshift & ALT) + xkey = Key_A_LftG; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_Rgt: + if(xshift & ALT) + xkey = Key_A_RgtG; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_PgUp: + if(xshift & ALT) + xkey = Key_A_PgUpG; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_PgDn: + if(xshift & ALT) + xkey = Key_A_PgDnG; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_Ins: + if(xshift & ALT) + xkey = Key_A_InsG; + else if(xshift & GCTRL) + xkey = Key_C_Ins; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + + case Key_Del: + if(xshift & ALT) + xkey = Key_A_DelG; + else if(xshift & GCTRL) + xkey = Key_C_Del; + if(xshift & (LSHIFT | RSHIFT)) + KCodScn(xkey) |= 0x80; + break; + } +} + + +// ------------------------------------------------------------------ + +extern int blanked; + +gkey getxch(int __tick) { + + gkey k; + + while(1) { + + // Keyboard polling loop + if(gkbd.polling) { + while(not kbmhit()) { + Clock thistick = gclock(); + long tickdiff = thistick - gkbd.tickvalue; + if(tickdiff < 0) { + gkbd.tickvalue = thistick; + tickdiff = gkbd.tickinterval + 1; + } + if(tickdiff >= gkbd.tickinterval) { + gkbd.tickvalue = thistick; + if(gkbd.tickfunc) { + gkbd.inidle = true; + (*gkbd.tickfunc)(); + gkbd.inidle = false; + } + if(__tick) + kbput(Key_Tick); + } + if(gmtsk.detected) + gmtsk.timeslice(); + } + } + + // Get key from internal buffer or keyboard + if(gkbd.kbuf) { + gkbd.source = GEVT_BUFFER; + k = gkbd.kbuf->xch; + KBuf* _kbuf = gkbd.kbuf->next; + throw_free(gkbd.kbuf); + gkbd.kbuf = _kbuf; + if(gkbd.kbuf) + gkbd.kbuf->prev = NULL; + } + else { + gkbd.source = GEVT_KEYBOARD; + k = kbxget(); + gkey s = kbxget(2); // Read shift status + if(not gkbd.extkbd) { + if(s & (LSHIFT|RSHIFT|GCTRL|ALT)) + makeextkey(s,k); + } + } + + // Note time of keypress unless it's a tick + if(k != Key_Tick) + gkbdtickpressreset(); + + // Search through onkey linked list for a + // matching defined onkey. If one is found, + // then save the current environment, call the + // onkey's function, and restore the environment. + + if(not blanked) { + KBnd* _onkey = gkbd.onkey; + while(_onkey) { + if(_onkey->keycode == k) { + gkbd.curronkey = _onkey; + kbd_call_func(_onkey->func); + #ifdef GOLD_MOUSE + if(gkbd.inmenu and gmou.FreeCursor()) + return 0; + #endif + break; + } + _onkey = _onkey->prev; + } + if(_onkey) { + if(not _onkey->pass or (_onkey->pass >= 0xFE00)) + k = 0; + else + k = _onkey->pass; + } + else { + + // Search for a menu hot key. If one is found, + // then save the current environment, call the + // hotkey's function, and restore the environment. + + if(gwin.menu) { + _item_t* item = find_hotkey(gwin.menu,k); + if(item) { + gwin.menu->hotkey = true; + kbd_call_func(item->select); + #ifdef GOLD_MOUSE + if(gkbd.inmenu and gmou.FreeCursor()) + return 0; + #endif + k = 0; + } + } + } + } + + // If we still have a keycode, exit the loop + if(k) + break; + } + + // Return keycode + return k; +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gkbdwait.cpp b/goldlib/gcui/gkbdwait.cpp new file mode 100644 index 0000000..a9c9c4b --- /dev/null +++ b/goldlib/gcui/gkbdwait.cpp @@ -0,0 +1,68 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Keyboard functions +// ------------------------------------------------------------------ + +#include +#include +#include +#include + + +// ------------------------------------------------------------------ +// Halts execution until a key is pressed + +gkey waitkey() { + + clearkeys(); + return getxch(); +} + + +// ------------------------------------------------------------------ +// Halts execution until a key is pressed or the specified time +// period has expired + +gkey waitkeyt(int duration) { + + clearkeys(); + Clock stop = gclock() + duration; + Clock sliced_time = gclock(); + while(1) { + if(kbmhit()) + return getxch(); + if(gclock() >= stop) + return 0; + if(gclock() - sliced_time >= 10) { + if(gkbd.tickfunc) + (*gkbd.tickfunc)(); + sliced_time = gclock(); + } + gmtsk.timeslice(); + } +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gmnubase.h b/goldlib/gcui/gmnubase.h new file mode 100644 index 0000000..af243ff --- /dev/null +++ b/goldlib/gcui/gmnubase.h @@ -0,0 +1,137 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Menu class. +// ------------------------------------------------------------------ + +#ifndef __gmnubase_h +#define __gmnubase_h + + +// ------------------------------------------------------------------ + +#include + + +// ------------------------------------------------------------------ +// Menu items + +typedef struct _item_t GMnuItm; + + +// ------------------------------------------------------------------ +// Menu class + +class GMnu { + +protected: + + int bordertype; + vattr bordercolor; + + vattr textcolor; + vattr quickcolor; + vattr noselcolor; + vattr barcolor; + vattr shadowcolor; + + const char* title; + int titlepos; + vattr titlecolor; + + int deschdl; + int descrow; + int desccolumn; + vattr desccolor; + + int helpnumber; + + int beginrow; + int begincolumn; + int beginwidth; + int beginheight; + + VfvCP menuopen; + int itemmask; + + int escape; + int overtag; + int finaltag; + int status; + + int depth; + struct { + int tag; + int type; + int winrow; + int wincolumn; + int winwidth; + int winheight; + int itemrow; + int itemcolumn; + } stack[10]; + +public: + + void Init(); + + void SetBorder(int type, vattr color); + void SetColor(vattr text, vattr quick, vattr nosel, vattr bar, vattr shadow = DEFATTR); + void SetTitle(const char* title, vattr color, int pos=TCENTER); + void SetTitle(const char* title); + void SetDesc(int hdl, int row, int col, vattr color); + void SetPos(int row, int col, int width=0, int height=0); + void SetEsc(int option); + void SetHelp(int help); + void SetMask(int mask); + void SetTag(int tag); + + void Begin(int type=M_VERT); + void BeginPullDown(int type=0) { Begin(M_VERT|M_PD|type); } + void End(); + void Start(); + + void Item(int tag, const char* text); + void Item(int tag, const char* text, int fmask); + void Item(int tag, const char* text, VfvCP select, int fmask=M_CLOSE); + void Item(int tag, const char* text, int fmask, VfvCP select, gkey hotkey=0); + void ItemDesc(const char* text); + void ItemSep(); + void ItemFuncs(VfvCP before, VfvCP after); + + void SetNextItem(int tag); + void DisableItem(int tag); + void EnableItem(int tag); + + GMnuItm* FindItem(int tag); + + int FinalTag() { return finaltag; } +}; + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gmoubase.cpp b/goldlib/gcui/gmoubase.cpp new file mode 100644 index 0000000..5b5d0d2 --- /dev/null +++ b/goldlib/gcui/gmoubase.cpp @@ -0,0 +1,456 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Mousing: class GMou member functions implementation. +// ------------------------------------------------------------------ + +#include +#include +#include + + +// ------------------------------------------------------------------ + +#ifdef GOLD_MOUSE + +// ------------------------------------------------------------------ + +GMou gmou; + + +// ------------------------------------------------------------------ + +GMou::GMou() { + + detected = false; + Reset(); +} + + +// ------------------------------------------------------------------ + +GMou::~GMou() { + + Reset(); +} + + +// ------------------------------------------------------------------ + +void GMou::SetLevel(int __level) { + + if(detected) { + level = __level; + if(level < GMOU_LEVEL_NONE) + level = GMOU_LEVEL_NONE; + else if(level > GMOU_LEVEL_FULL) + level = GMOU_LEVEL_FULL; + } + else { + level = GMOU_LEVEL_NONE; + } +} + + +// ------------------------------------------------------------------ + +void GMou::Reset() { + + level = GMOU_LEVEL_NONE; + hidden = 1; + hit.button = 0; + hit.count = 0; + hit.row = 0; + hit.column = 0; + if(detected) + Init(); +} + + +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +// DOS MOUSING - BEGIN +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ + +#if defined(__MSDOS__) + + +// ------------------------------------------------------------------ + +void GMou::Init() { + + i86 cpu; + cpu.ax(MSMOUSE_RESET_DRIVER); + cpu.genint(MSMOUSE_INT); + if(cpu.ax()) + detected = true; +} + + +// ------------------------------------------------------------------ + +void GMou::ClearEvents() { + + if(level) { + i86 cpu; + cpu.ax(MSMOUSE_GET_BUTTON_PRESS); + cpu.bx(GMOU_LEFT_BUTTON); + cpu.genint(MSMOUSE_INT); + cpu.ax(MSMOUSE_GET_BUTTON_PRESS); + cpu.bx(GMOU_RIGHT_BUTTON); + cpu.genint(MSMOUSE_INT); + cpu.ax(MSMOUSE_GET_BUTTON_RELEASE); + cpu.bx(GMOU_LEFT_BUTTON); + cpu.genint(MSMOUSE_INT); + cpu.ax(MSMOUSE_GET_BUTTON_RELEASE); + cpu.bx(GMOU_RIGHT_BUTTON); + cpu.genint(MSMOUSE_INT); + } +} + + +// ------------------------------------------------------------------ + +void GMou::GetStatus() { + + if(level) { + i86 cpu; + cpu.ax(MSMOUSE_GET_BUTTONS_AND_POSITION); + cpu.genint(MSMOUSE_INT); + hit.button = cpu.bx(); + hit.count = 0; + hit.column = cpu.cx() / gvid->curr.screen.cwidth; + hit.row = cpu.dx() / gvid->curr.screen.cheight; + } +} + + +// ------------------------------------------------------------------ + +void GMou::GetPress(int __button) { + + if(level) { + i86 cpu; + cpu.ax(MSMOUSE_GET_BUTTON_PRESS); + cpu.bx((word)__button); + cpu.genint(MSMOUSE_INT); + hit.button = cpu.ax(); + hit.count = cpu.bx(); + hit.column = cpu.cx() / gvid->curr.screen.cwidth; + hit.row = cpu.dx() / gvid->curr.screen.cheight; + } +} + + +// ------------------------------------------------------------------ + +void GMou::GetRelease(int __button) { + + if(level) { + i86 cpu; + cpu.ax(MSMOUSE_GET_BUTTON_RELEASE); + cpu.bx((word)__button); + cpu.genint(MSMOUSE_INT); + hit.button = cpu.ax(); + hit.count = cpu.bx(); + hit.column = cpu.cx() / gvid->curr.screen.cwidth; + hit.row = cpu.dx() / gvid->curr.screen.cheight; + } +} + + +// ------------------------------------------------------------------ + +void GMou::SetCursor(int __curtype, int __smask, int __cmask) { + + if(level) { + i86 cpu; + cpu.ax(MSMOUSE_SET_TEXT_CURSOR); + cpu.bx((word)__curtype); + cpu.cx((word)__smask); + cpu.dx((word)__cmask); + cpu.genint(MSMOUSE_INT); + } +} + + +// ------------------------------------------------------------------ + +void GMou::SetPosition(int __row, int __col) { + + if(level) { + i86 cpu; + cpu.ax(MSMOUSE_SET_CURSOR_POSITION); + cpu.cx((word)(__col * gvid->curr.screen.cwidth)); + cpu.dx((word)(__row * gvid->curr.screen.cheight)); + cpu.genint(MSMOUSE_INT); + } +} + + +// ------------------------------------------------------------------ + +void GMou::HideCursor() { + + if(level) { + if(not hidden) { + i86 cpu; + cpu.ax(MSMOUSE_HIDE_CURSOR); + cpu.genint(MSMOUSE_INT); + hidden = true; + } + } +} + + +// ------------------------------------------------------------------ + +void GMou::ShowCursor() { + + if(level) { + i86 cpu; + cpu.ax(MSMOUSE_SHOW_CURSOR); + cpu.genint(MSMOUSE_INT); + hidden = false; + } +} + + +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +// DOS MOUSING - END +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ + +#endif + + +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +// OS/2 MOUSING - BEGIN +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ + +#if defined(__OS2__) + + +// ------------------------------------------------------------------ + +void GMou::Init() { + + #if 0 + if(MouOpen(NULL, &hmou) == 0) { + USHORT _mask = MOUSE_BN1_DOWN|MOUSE_BN2_DOWN|MOUSE_BN3_DOWN; + MouSetEventMask(&_mask, hmou); + detected = true; + } + #endif +} + + +// ------------------------------------------------------------------ + +void GMou::ClearEvents() { + + if(level) { + MouFlushQue(hmou); + } +} + + +// ------------------------------------------------------------------ + +void GMou::GetStatus() { + + if(level) { + PTRLOC _pos; + MouGetPtrPos(&_pos, hmou); + hit.button = 0; + hit.count = 0; + hit.column = _pos.col; + hit.row = _pos.row; + MOUEVENTINFO _event; + USHORT _wait = MOU_NOWAIT; + if(MouReadEventQue(&_event, &_wait, hmou) == 0) { + if(_event.fs & (MOUSE_BN1_DOWN|MOUSE_MOTION_WITH_BN1_DOWN)) + hit.button |= GMOU_LEFT_PRESSED; + if(_event.fs & (MOUSE_BN2_DOWN|MOUSE_MOTION_WITH_BN2_DOWN)) + hit.button |= GMOU_RIGHT_PRESSED; + if(_event.fs & (MOUSE_BN3_DOWN|MOUSE_MOTION_WITH_BN3_DOWN)) + hit.button |= GMOU_MIDDLE_PRESSED; + } + } +} + + +// ------------------------------------------------------------------ + +void GMou::GetPress(int __button) { + + NW(__button); + #if 0 + if(level) { + hit.button = 0; + hit.count = 0; + hit.column = 0; + hit.row = 0; + MOUQUEINFO _que; + MouGetNumQueEl(&_que, hmou); + hit.count = _que.cEvents; + if(hit.count) { + MOUEVENTINFO _event; + USHORT _wait = MOU_WAIT; + if(MouReadEventQue(&_event, &_wait, hmou) == 0) { + if(_event.fs & (MOUSE_BN1_DOWN|MOUSE_MOTION_WITH_BN1_DOWN)) + hit.button |= GMOU_LEFT_PRESSED; + if(_event.fs & (MOUSE_BN2_DOWN|MOUSE_MOTION_WITH_BN2_DOWN)) + hit.button |= GMOU_RIGHT_PRESSED; + if(_event.fs & (MOUSE_BN3_DOWN|MOUSE_MOTION_WITH_BN3_DOWN)) + hit.button |= GMOU_MIDDLE_PRESSED; + hit.column = _event.col; + hit.row = _event.row; + } + } + } + #endif +} + + +// ------------------------------------------------------------------ + +void GMou::GetRelease(int __button) { + + NW(__button); + #if 0 + if(level) { + hit.button = 0; + hit.count = 0; + hit.column = 0; + hit.row = 0; + MOUQUEINFO _que; + MouGetNumQueEl(&_que, hmou); + hit.count = _que.cEvents; + if(hit.count) { + MOUEVENTINFO _event; + USHORT _wait = MOU_WAIT; + if(MouReadEventQue(&_event, &_wait, hmou) == 0) { + if(_event.fs & (MOUSE_BN1_DOWN|MOUSE_MOTION_WITH_BN1_DOWN)) + hit.button |= GMOU_LEFT_PRESSED; + if(_event.fs & (MOUSE_BN2_DOWN|MOUSE_MOTION_WITH_BN2_DOWN)) + hit.button |= GMOU_RIGHT_PRESSED; + if(_event.fs & (MOUSE_BN3_DOWN|MOUSE_MOTION_WITH_BN3_DOWN)) + hit.button |= GMOU_MIDDLE_PRESSED; + hit.column = _event.col; + hit.row = _event.row; + } + } + } + #endif +} + + +// ------------------------------------------------------------------ + +void GMou::SetCursor(int __curtype, int __smask, int __cmask) { + + if(level) { + // Not implemented yet + NW(__curtype); + NW(__smask); + NW(__cmask); + } +} + + +// ------------------------------------------------------------------ + +void GMou::SetPosition(int __row, int __col) { + + if(level) { + PTRLOC _pos; + _pos.row = (USHORT)__row; + _pos.col = (USHORT)__col; + MouSetPtrPos(&_pos, hmou); + } +} + + +// ------------------------------------------------------------------ + +void GMou::HideCursor() { + + if(level) { + if(not hidden) { + NOPTRRECT _rect; + _rect.row = 0; + _rect.col = 0; + _rect.cRow = (USHORT)(gvid->curr.screen.rows-1); + _rect.cCol = (USHORT)(gvid->curr.screen.columns-1); + MouRemovePtr(&_rect, hmou); + hidden = true; + } + } +} + + +// ------------------------------------------------------------------ + +void GMou::ShowCursor() { + + if(level) { + MouDrawPtr(hmou); + hidden = false; + } +} + + +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ +// OS/2 MOUSING - END +// ------------------------------------------------------------------ +// ------------------------------------------------------------------ + +#endif + + +// ------------------------------------------------------------------ +// Dummy definitions when mouse support is not defined + +void GMou::Init() {} +void GMou::ClearEvents() {} +void GMou::GetStatus() {} +void GMou::GetPress(int) {} +void GMou::GetRelease(int) {} +void GMou::SetCursor(int, int, int) {} +void GMou::SetPosition(int, int) {} +void GMou::HideCursor() {} +void GMou::ShowCursor() {} + + +// ------------------------------------------------------------------ + +#endif // GOLD_MOUSE + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gmoubase.h b/goldlib/gcui/gmoubase.h new file mode 100644 index 0000000..aabfee9 --- /dev/null +++ b/goldlib/gcui/gmoubase.h @@ -0,0 +1,174 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Mousing (declarations). +// ------------------------------------------------------------------ + +#ifndef __gmoubase_h +#define __gmoubase_h + + +// ------------------------------------------------------------------ + +#include + + +// ------------------------------------------------------------------ + +#ifdef GOLD_MOUSE + +// ------------------------------------------------------------------ +// Mouse constants + +const int GMOU_LEVEL_NONE = 0; // No mouse support +const int GMOU_LEVEL_KEYS = 1; // Mouse movement emulates arrow keys +const int GMOU_LEVEL_CURS = 2; // Free-moving mouse cursor where supported +const int GMOU_LEVEL_FULL = 3; // Full mouse support (MS_KEYS | MS_CURS) + +const int GMOU_EVENT_MAX = 10; + +const int GMOU_LEFT_BUTTON = 0x00; +const int GMOU_RIGHT_BUTTON = 0x01; + +const int GMOU_LEFT_PRESSED = 0x01; +const int GMOU_RIGHT_PRESSED = 0x02; +const int GMOU_MIDDLE_PRESSED = 0x04; + +const int GMOU_MOVED = 0x01; + +const int GMOU_PRESSED_LEFT = 0x02; +const int GMOU_RELEASED_LEFT = 0x04; +const int GMOU_PRESSED_RIGHT = 0x08; +const int GMOU_RELEASED_RIGHT = 0x10; +const int GMOU_PRESSED_MIDDLE = 0x20; +const int GMOU_RELEASED_MIDDLE = 0x40; + +const int GMOU_EVENT_LEFT = GMOU_PRESSED_LEFT | GMOU_RELEASED_LEFT; +const int GMOU_EVENT_RIGHT = GMOU_PRESSED_RIGHT | GMOU_RELEASED_RIGHT; +const int GMOU_EVENT_MIDDLE = GMOU_PRESSED_MIDDLE | GMOU_RELEASED_MIDDLE; + + +// ------------------------------------------------------------------ +// MS MOUSE interrupt + +const word MSMOUSE_INT = 0x33; + + +// ------------------------------------------------------------------ +// MS MOUSE functions + +const word MSMOUSE_RESET_DRIVER = 0x00; +const word MSMOUSE_SHOW_CURSOR = 0x01; +const word MSMOUSE_HIDE_CURSOR = 0x02; +const word MSMOUSE_GET_BUTTONS_AND_POSITION = 0x03; +const word MSMOUSE_SET_CURSOR_POSITION = 0x04; +const word MSMOUSE_GET_BUTTON_PRESS = 0x05; +const word MSMOUSE_GET_BUTTON_RELEASE = 0x06; +const word MSMOUSE_SET_HORIZONTAL_RANGE = 0x07; +const word MSMOUSE_SET_VERTIAL_RANGE = 0x08; +const word MSMOUSE_SET_GRAPHICS_CURSOR = 0x09; +const word MSMOUSE_SET_TEXT_CURSOR = 0x0A; + + +// ------------------------------------------------------------------ +// Mouse class + +class GMou { + + #if 0 + #ifdef __OS2__ + HMOU hmou; + #endif + #endif + +public: + + int detected; // true if a mouse driver was detected + int level; // Mouse support level (GMOU_LEVEL_xxxx) + int hidden; // Depth of cursor hides + + struct { + int button; + int count; + int row; + int column; + } hit; + + GMou(); + ~GMou(); + + void SetLevel(int __level); + + void Reset(); + void Init(); + + void ClearEvents(); + + void GetStatus(); + void GetPress(int __button); + void GetRelease(int __button); + + void SetCursor(int __curtype, int __smask, int __cmask); + + void SetPosition(int __row, int __col); + + void HideCursor(); + void ShowCursor(); + + int Hidden() { return make_bool(hidden); } + + int Enabled() { return level > GMOU_LEVEL_NONE; } + + int FreeCursor() { return level & GMOU_LEVEL_CURS; } + int KeysEmulate() { return level & GMOU_LEVEL_KEYS; } + + int Button() { return hit.button; } + int LeftButton() { return hit.button & GMOU_LEFT_PRESSED; } + int RightButton() { return hit.button & GMOU_RIGHT_PRESSED; } + int MiddleButton() { return hit.button & GMOU_MIDDLE_PRESSED; } + int Count() { return hit.count; } + int Row() { return hit.row; } + int Column() { return hit.column; } + + void GetLeftPress() { GetPress(GMOU_LEFT_BUTTON); } + void GetRightPress() { GetPress(GMOU_RIGHT_BUTTON); } + + void GetLeftRelease() { GetRelease(GMOU_LEFT_BUTTON); } + void GetRightRelease() { GetRelease(GMOU_RIGHT_BUTTON); } +}; + +extern GMou gmou; + + +// ------------------------------------------------------------------ + +#endif // GOLD_MOUSE + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ + + diff --git a/goldlib/gcui/gsrchmgr.cpp b/goldlib/gcui/gsrchmgr.cpp new file mode 100644 index 0000000..57398a5 --- /dev/null +++ b/goldlib/gcui/gsrchmgr.cpp @@ -0,0 +1,95 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Search manager. +// ------------------------------------------------------------------ + +#include + + +// ------------------------------------------------------------------ + +search_item::search_item() { + + logic = logic_or; + + where.from = false; + where.to = false; + where.subject = false; + where.body = false; + where.tagline = false; + where.tearline = false; + where.origin = false; + where.signature = false; + where.kludges = false; +} + + +// ------------------------------------------------------------------ + +search_item::~search_item() { + +} + + +// ------------------------------------------------------------------ + +search_item& search_item::operator=(const search_item& a) { + + gsearch::operator=(a); + + logic = a.logic; + where.from = a.where.from; + where.to = a.where.to; + where.subject = a.where.subject; + where.body = a.where.body; + where.tagline = a.where.tagline; + where.tearline = a.where.tearline; + where.origin = a.where.origin; + where.signature = a.where.signature; + where.kludges = a.where.kludges; + + return *this; +} + + +// ------------------------------------------------------------------ + +search_manager::search_manager() : gwinput2(window) { + + direction = direction_forward; + messages = messages_new; + action = action_read; + areas = areas_current; +} + + +// ------------------------------------------------------------------ + +search_manager::~search_manager() { + +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gsrchmgr.h b/goldlib/gcui/gsrchmgr.h new file mode 100644 index 0000000..dc9f329 --- /dev/null +++ b/goldlib/gcui/gsrchmgr.h @@ -0,0 +1,143 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Search manager. +// ------------------------------------------------------------------ + +#ifndef __gsrchmgr_h +#define __gsrchmgr_h + + +// ------------------------------------------------------------------ + +#include +#include +#include +#include + + +// ------------------------------------------------------------------ + +class search_item : public gsearch { + +public: + + enum item_logic { + logic_and, + logic_or + }; + + struct item_where { + bool from; + bool to; + bool subject; + bool body; + bool tagline; + bool tearline; + bool origin; + bool signature; + bool kludges; + }; + + item_logic logic; + item_where where; + + search_item(); + virtual ~search_item(); + + search_item& operator=(const search_item& a); + +}; + + +// ------------------------------------------------------------------ + +class search_manager : public gwinput2 { + +public: + + enum { + if_nothing, + id_pattern1, id_logic1, id_options1, + id_pattern2, id_logic2, id_options2, + id_pattern3, id_logic3, id_options3, + id_pattern4, id_logic4, id_options4, + id_pattern5, id_logic5, id_options5, + id_pattern6, id_logic6, id_options6, + id_pattern7, id_logic7, id_options7, + id_pattern8, id_logic8, id_options8, + id_pattern9, id_logic9, id_options9, + id_direction, + id_messages, + id_action, + id_areas + }; + + enum search_direction { + direction_backward, + direction_forward + }; + + enum search_messages { + messages_new, + messages_unread, + messages_all + }; + + enum search_action { + action_read, + action_mark, + action_delete, + action_write, + action_copy, + action_move + }; + + enum search_areas { + areas_current, + areas_tagged, + areas_all + }; + + std::vector items; + + search_direction direction; + search_messages messages; + search_action action; + search_areas areas; + + gwindow window; + + search_manager(); + virtual ~search_manager(); + +}; + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gvidall.h b/goldlib/gcui/gvidall.h new file mode 100644 index 0000000..f7269c7 --- /dev/null +++ b/goldlib/gcui/gvidall.h @@ -0,0 +1,469 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Screen/video functions. +// Based on CXL by Mike Smedley. +// ------------------------------------------------------------------ + +#ifndef __gvidall_h +#define __gvidall_h + + +// ------------------------------------------------------------------ + +#include +#if defined(__USE_NCURSES__) +#include +#endif +#if defined(__WIN32__) +#include +#endif + +#if defined(_MSC_VER) +#pragma warning(disable: 4200) +#endif + + +// ------------------------------------------------------------------ + +#ifdef BLINK +#undef BLINK +#endif +#define BLINK 128 + +#ifdef INTENSE +#undef INTENSE +#endif +#define INTENSE 8 + +#if defined(__UNIX__) && !defined(__USE_NCURSES__) +#define ACSET BLINK +#else +#define ACSET 0 +#endif + + +// ------------------------------------------------------------------ + +#if defined(__USE_NCURSES__) +typedef chtype vchar; // Type of characters on-screen +typedef int vattr; // Type of screen attributes +typedef chtype vatch; // Type of character-attribute groups +#elif defined(__WIN32__) +typedef char vchar; // Type of characters on-screen +typedef int vattr; // Type of screen attributes +typedef CHAR_INFO vatch; // Type of character-attribute groups +#else +typedef char vchar; // Type of characters on-screen +typedef int vattr; // Type of screen attributes +typedef word vatch; // Type of character-attribute groups +#endif + + +// ------------------------------------------------------------------ +// Attribute codes for functions that use them + +const vattr DEFATTR = -1; + +const vattr BLACK_ = 0; +const vattr BLUE_ = 1; +const vattr GREEN_ = 2; +const vattr CYAN_ = 3; +const vattr RED_ = 4; +const vattr MAGENTA_ = 5; +const vattr BROWN_ = 6; +const vattr LGREY_ = 7; +const vattr DGREY_ = 8; +const vattr LBLUE_ = 9; +const vattr LGREEN_ = 10; +const vattr LCYAN_ = 11; +const vattr LRED_ = 12; +const vattr LMAGENTA_ = 13; +const vattr YELLOW_ = 14; +const vattr WHITE_ = 15; + +const vattr _BLACK = (BLACK_ << 4); +const vattr _BLUE = (BLUE_ << 4); +const vattr _GREEN = (GREEN_ << 4); +const vattr _CYAN = (CYAN_ << 4); +const vattr _RED = (RED_ << 4); +const vattr _MAGENTA = (MAGENTA_ << 4); +const vattr _BROWN = (BROWN_ << 4); +const vattr _LGREY = (LGREY_ << 4); +const vattr _DGREY = (DGREY_ << 4); +const vattr _LBLUE = (LBLUE_ << 4); +const vattr _LGREEN = (LGREEN_ << 4); +const vattr _LCYAN = (LCYAN_ << 4); +const vattr _LRED = (LRED_ << 4); +const vattr _LMAGENTA = (LMAGENTA_<< 4); +const vattr _YELLOW = (YELLOW_ << 4); +const vattr _WHITE = (WHITE_ << 4); + + +// ------------------------------------------------------------------ +// Additional monochrome color values + +const vattr UNDERLINE = 1; +const vattr NORMAL = 7; +const vattr HIGHLIGHT = 15; +const vattr REVERSE = 112; + + +// ------------------------------------------------------------------ +// Display adapter types returned from vidtype() +// If bit 0 is set, the adapter was detected in monochrome mode + +#define GV_NONE 0x0000 +#define V_MONO 0x0001 +#define V_MDA 0x0011 +#define V_HGC 0x0021 +#define V_HGCPLUS 0x0041 +#define V_INCOLOR 0x0080 +#define V_CGA 0x0100 +#define V_EGA 0x0200 +#define V_EGAMONO 0x0201 +#define V_MCGA 0x0400 +#define V_MCGAMONO 0x0401 +#define V_VGA 0x0800 +#define V_VGAMONO 0x0801 + + +// ------------------------------------------------------------------ +// Video parameter settings + +#define VP_DMA 0 // direct screen writes +#define VP_CGA 1 // direct screen writes, eliminate CGA snow +#define VP_BIOS 2 // BIOS screen writes +#define VP_MONO 3 // monochrome attribute translation on +#define VP_COLOR 4 // monochrome attribute translation off +#define VP_OS2VIO 6 // OS/2 vio screen writes +#define VP_W32CON 7 // WIN32 console screen writes +#define VP_CURSES 8 // Curses screen writes + + +// ------------------------------------------------------------------ +// Video devices + +#define GVID_DMA 0 +#define GVID_CGA 1 +#define GVID_BIO 2 +#define GVID_OS2 4 +#define GVID_W32 5 +#define GVID_CUR 6 + + +// ------------------------------------------------------------------ +// Useful defines for video (0x10) interrupt function numbers + +#if defined(__MSDOS__) +#define V_SET_MODE 0x00 +#define V_SET_CURSOR_POS 0x02 +#define V_GET_CURSOR_POS 0x03 +#define V_SCROLL_UP 0x06 +#define V_SCROLL_DOWN 0x07 +#define V_RD_CHAR_ATTR 0x08 +#define V_WR_CHAR_ATTR 0x09 +#define V_WR_CHAR 0x0A +#define V_WR_TTY 0x0E +#define V_GET_MODE 0x0F +#define V_GET_FONT_INFO 0x1130 +#endif + + +// ------------------------------------------------------------------ + +#if defined(__MSDOS__) +struct __int10_ah1b_statebuf { + // Offset Size Description + dword statfunctable; // 00h DWORD address of static funtionality table (see below) + byte videomode; // 04h BYTE video mode in effect + word columns; // 05h WORD number of columns + word regenbuflen; // 07h WORD length of regen buffer in bytes + word regenbufstart; // 09h WORD starting address of regen buffer + word cursorpos0; // 0Bh WORD cursor position for page 0 + word cursorpos1; // 0Dh WORD cursor position for page 1 + word cursorpos2; // 0Fh WORD cursor position for page 2 + word cursorpos3; // 11h WORD cursor position for page 3 + word cursorpos4; // 13h WORD cursor position for page 4 + word cursorpos5; // 15h WORD cursor position for page 5 + word cursorpos6; // 17h WORD cursor position for page 6 + word cursorpos7; // 19h WORD cursor position for page 7 + word cursortype; // 1Bh WORD cursor type + byte activepage; // 1Dh BYTE active display page + word crctportaddr; // 1Eh WORD CRTC port address + byte curr_reg_3x8; // 20h BYTE current setting of register (3?8) + byte curr_reg_3x9; // 21h BYTE current setting of register (3?9) + byte rows; // 22h BYTE number of rows + word bytesperchar; // 23h WORD bytes/character + byte dispcombcode; // 25h BYTE display combination code of active display + byte dcc; // 26h BYTE DCC of alternate display + word numcolors; // 27h WORD number of colors supported in current mode + byte numpages; // 29h BYTE number of pages supported in current mode + byte numscanlines; // 2Ah BYTE number of scan lines active (0,1,2,3) = (200,350,400,480) Tseng ET3000: (4,5,6 = 512,600,768) + byte primcharblock; // 2Bh BYTE primary character block + byte seccharblock; // 2Ch BYTE secondary character block + byte miscflags; // 2Dh BYTE miscellaneous flags (see below) + byte reserved1[3]; // 2Eh 3 BYTEs reserved (00h) + byte videomem; // 31h BYTE video memory available 00h = 64K, 01h = 128K, 02h = 192K, 03h = 256K + byte stateflags; // 32h BYTE save pointer state flags (see below) + byte reserved2[13]; // 33h 13 BYTEs reserved (00h) +}; +#endif + + +// ------------------------------------------------------------------ +// Border types + +#define BT_SINGLE 0 +#define BT_DOUBLE 1 +#define BT_SINGLETOP 2 +#define BT_DOUBLETOP 3 +#define BT_BLANKS 4 +#define BT_NONE 5 +#define BT_BLOCKS 6 +#define BT_ASCII 7 + + +// ------------------------------------------------------------------ +// Video information structure + +struct GVidInfo { + + // Screen info + struct _screen + { + int mode; // Video mode + int rows; // Number of rows + int columns; // Number of columns + int cheight; // Character height + int cwidth; // Character width + } screen; + + // Cursor info + struct _cursor + { + int column; // Cursor column + int row; // Cursor row + int start; // Cursor start line + int end; // Cursor end line + word attr; // Cursor attribute. Hidden if attr == 0xFFFF + } cursor; + + // Colors + struct _color + { + vattr textattr; // Text attribute + vattr overscan; // Overscan color + int intensity; // Background color state (intense or blinking) + int palette[16]; // Palette state + } color; +}; + + +// ------------------------------------------------------------------ + +#ifdef __DJGPP__ +typedef uint32_t gdma; // Video DMA linear address +#else +typedef word* gdma; // Video DMA pointer +#endif + +// ------------------------------------------------------------------ +// Video information record + +class GVid { + +public: + + int adapter; // Video adapter type + + GVidInfo orig; // Original video info + GVidInfo curr; // Current video info + + int device; // Video device type + + gdma dmadir; // Video DMA pointer (direct) + gdma dmaptr; // Video DMA pointer (direct or buffered) + + vchar* bufchr; // Video line char buffer (char only) + vatch* bufwrd; // Video line word buffer (char+attr) + vchar* bufansi; // Video line ANSI buffer (11*numcols) + + int currow; // Current cursor row + int curcol; // Current cursor column + + size_t numrows; // number of displayed rows + size_t numcols; // number of displayed columns + + word videoseg; // video buffer segment address + +public: + + GVid(); + ~GVid(); + +public: + + void init(); + + int detectadapter (); + void detectinfo (GVidInfo* _info); + static + void setcolorpairs (bool enabletransparent=false); + + void resetcurr (); + + void setdevice (int _device); + + void setmode (int _mode); + void setrows (int _rows); + + void setoverscan (vattr _overscan); + void setintensity (int _intensity); + + void getpalette (int* _palette); + void setpalette (int* _palette); + + bool isdma() { return device == GVID_DMA; } + bool iscga() { return device == GVID_CGA; } + bool isbios() { return device == GVID_BIO; } + + void restore_cursor(); + + void resize_screen(int columns, int rows); + +}; + +extern GVid *gvid; + + +// ------------------------------------------------------------------ +// Box characters table + +#if !defined(__USE_NCURSES__) + +extern char* __box_table[]; +#define _box_table(i,j) (__box_table[i][j]) + +#else + +chtype _box_table(int type, int c); + +#endif + + +// ------------------------------------------------------------------ +// Prototypes + +int setvparam (int setting); + +vattr mapattr (vattr attr); +vattr revsattr (vattr attr); + +inline vattr attrib(int f, int b, int i, int bl) { return (int)((b<<4)|(f)|(i<<3)|(bl<<7)); } + +void vputw (int row, int col, vatch chat); +void vputws (int row, int col, vatch* buf, uint len); +void vputc (int row, int col, vattr atr, vchar chr); +void vputvs (int row, int col, vattr atr, const vchar* str); +void vputs (int row, int col, vattr atr, const char* str); +void vputs_box (int row, int col, vattr atr, const char* str); +void vputns (int row, int col, vattr atr, const char* str, uint len); +void vputx (int row, int col, vattr atr, vchar chr, uint len); +void vputy (int row, int col, vattr atr, vchar chr, uint len); + +vatch vgetw (int row, int col); +void vgetc (int row, int col, vattr* atr, vchar* chr); + +void vscroll (int srow, int scol, int erow, int ecol, vattr atr, int lines); + +void vposget (int* row, int* col); +void vposset (int row, int col); + +void vclrscr (); +void vclrscr (vattr atr); // Overloaded + +typedef struct _vsavebuf { + int top, left, right, bottom; + __extension__ vatch data[0]; +} vsavebuf; +vsavebuf* vsave (int srow=-1, int scol=-1, int erow=-1, int ecol=-1); +void vrestore (vsavebuf* buf, int srow=-1, int scol=-1, int erow=-1, int ecol=-1); + +void vcurget (int* sline, int* eline); +void vcurset (int sline, int eline); + +void vcurhide (); +void vcurshow (); +bool vcurhidden (); + +void vcurlarge (); +void vcursmall (); + +void vbox (int srow, int scol, int erow, int ecol, int box, vattr hiattr, vattr loattr = DEFATTR); +void vfill (int srow, int scol, int erow, int ecol, vchar chr, vattr atr); + + +#if defined(__USE_NCURSES__) + +int gvid_dosattrcalc (int ourattr); +int gvid_attrcalc (int dosattr); + +inline vchar vgchar (vatch chat) { return chat & (A_CHARTEXT | A_ALTCHARSET); } +inline vattr vgattr (vatch chat) { return gvid_dosattrcalc(chat & ~(A_CHARTEXT | A_ALTCHARSET)); } +inline vatch vschar (vatch chat, vchar chr) { return (chr & (A_CHARTEXT | A_ALTCHARSET)) | (chat & ~(A_CHARTEXT | A_ALTCHARSET)); } +inline vatch vsattr (vatch chat, vattr atr) { return (chat & (A_CHARTEXT | A_ALTCHARSET)) | gvid_attrcalc(atr); } +inline vatch vcatch (vchar chr, vattr atr) { return chr | gvid_attrcalc(atr); } + +#elif defined(__WIN32__) + +inline vchar vgchar (vatch chat) { return chat.Char.AsciiChar; } +inline vattr vgattr (vatch chat) { return chat.Attributes; } +inline vatch vschar (vatch chat, vchar chr) { chat.Char.UnicodeChar = 0; chat.Char.AsciiChar = chr; return chat; } +inline vatch vsattr (vatch chat, vattr atr) { chat.Attributes = WORD(atr); return chat; } +inline vatch vcatch (vchar chr, vattr atr) { vatch chat; chat.Char.UnicodeChar = 0; chat.Char.AsciiChar = chr; chat.Attributes = WORD(atr); return chat; } + +#else + +inline vchar vgchar (vatch chat) { return chat & 0xff; } +inline vattr vgattr (vatch chat) { return (chat >> 8) & 0xff; } +inline vatch vschar (vatch chat, vchar chr) { return (chat & 0xff00) | chr; } +inline vatch vsattr (vatch chat, vattr atr) { return (chat & 0xff) | (atr << 8); } +inline vatch vcatch (vchar chr, vattr atr) { return (chr & 0xff) | ((atr << 8) & 0xff00); } + +#endif + +inline vchar vgetc (int row, int col) { return vgchar(vgetw(row, col)); } + +typedef void (*VidPutStrCP)(int,int,int,const char*); + +void gvid_boxcvt(char* s); + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gvidbase.cpp b/goldlib/gcui/gvidbase.cpp new file mode 100644 index 0000000..41dd9b7 --- /dev/null +++ b/goldlib/gcui/gvidbase.cpp @@ -0,0 +1,2189 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// Copyright (C) 2000 Jacobo Tarrio +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Device-independent video functions. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__OS2__) +#define INCL_BASE +#include +#ifndef __EMX__ +#define PCCH CHAR* +#endif +#endif + +#ifdef __WIN32__ +#include +#endif + +#ifdef __GNUC__ +#include +#endif + +#if defined(__DJGPP__) +#include +#endif + + +// ------------------------------------------------------------------ +// Check if Borland C++ for OS/2 1.0 header has been fixed + +#if defined(__OS2__) && defined(__BORLANDC__) + #if __BORLANDC__ <= 0x400 + #ifndef BCOS2_BSESUB_FIXED + #error There is a bug in the BSESUB.H header. Please fix it. + // + // Add/change the following in BSESUB.H: + // + // #define BCOS2_BSESUB_FIXED + // APIRET16 APIENTRY16 VioGetState (PVOID16 pState, HVIO hvio); + // APIRET16 APIENTRY16 VioSetState (PVOID16 pState, HVIO hvio); + // + // Borland forgot this (was only PVOID) ^^ + // + #endif + #endif +#endif + + +// ------------------------------------------------------------------ + +static bool __vcurhidden = false; +#if defined(__UNIX__) || defined(__USE_NCURSES__) +static uint32_t gvid_boxcvtc(char); +#endif + +#if !defined(__USE_NCURSES__) + +// ------------------------------------------------------------------ + +#ifdef __WIN32__ +extern HANDLE gvid_hout; +extern OSVERSIONINFO WinVer; // defined in gutlwin.cpp +extern WCHAR oem2unicode[]; // defined in gutlwin.cpp + +// ------------------------------------------------------------------ +// Transform character < 32 into printable Unicode equivalent + + +inline WCHAR gvid_tcpr(vchar chr) { + + return oem2unicode[chr & 0xff]; +} + +#endif + + +// ------------------------------------------------------------------ + +#if defined(__MSDOS__) || defined(__UNIX__) + +#if defined(__MSDOS__) +extern int __gdvdetected; +#endif + +#ifndef __DJGPP__ +const uint16_t _dos_ds = 0; + +inline uint16_t _my_ds(void) { + + return 0; +} + +inline void _farpokew(uint16_t s, gdma ptr, word chat) { + + NW(s); + *ptr = chat; +} + +inline void _farnspokew(gdma ptr, word chat) { + + *ptr = chat; +} + +inline word _farpeekw(uint16_t s, gdma ptr) { + + NW(s); + return *ptr; +} + +inline void _farnspokeb(byte *ptr, byte chr) { + + *ptr = chr; +} + +inline void _farsetsel(uint16_t s) { + + NW(s); +} +#endif + +#ifdef __DJGPP__ +const int ATTRSIZE = sizeof(word); +#else +const int ATTRSIZE = 1; +#endif + +inline void gdmacpy(uint16_t seg_d, gdma sel_d, uint16_t seg_s, gdma sel_s, int len) { + + #ifdef __DJGPP__ + movedata(seg_s, sel_s, seg_d, sel_d, len); + #else + NW(seg_d); + NW(seg_s); + memcpy(sel_d, sel_s, len); + #endif +} + +inline gdma gdmaptr(int col, int row) { + + return gvid->dmaptr+ATTRSIZE*((row*gvid->numcols)+col); +} +#endif + + +// ------------------------------------------------------------------ + +#if defined(__UNIX__) + + +// ------------------------------------------------------------------ + +extern int gvid_stdout; +extern const char* gvid_acs_enable; +extern const char* gvid_acs_disable; +int gvid_last_attr = 0; + + +// ------------------------------------------------------------------ + +void gvid_printf(const char* fmt, ...) { + + char buf[1024]; + va_list argptr; + va_start(argptr, fmt); + int n = vsprintf(buf, fmt, argptr); + va_end(argptr); + + write(gvid_stdout, buf, n); +} + + +// ------------------------------------------------------------------ +// Control chars 01234567890123456789012345678901 + +const char* gvid_x0 = "x@xxxxxxxxxxxxxx>>4) & 7]; +} + + +// ------------------------------------------------------------------ + +void vputansi(int row, int col, word* buf, int len) { + + char ch; + int in, fg, bg, acs; + int atr = gvid_last_attr; + int in0 = vatr2ansin(atr); + int fg0 = vatr2ansfg(atr); + int bg0 = vatr2ansbg(atr); + int acs0 = atr & ACSET; + + // Get pointer to ANSI line buffer + char* ptr = gvid->bufansi; + + // Get pointer to video memory image + byte* p = (byte*)buf; + + for(int n=0; nbufansi); +} + + +// ------------------------------------------------------------------ + +#endif + +#endif // !defined(__USE_NCURSES__) + + +// ------------------------------------------------------------------ +// Converts an attribute to monochrome equivalent + +vattr mapattr(vattr attr) +{ + switch(attr&112) { // test for a light background + + case _LGREY: + case _GREEN: + case _CYAN: + case _BROWN: + attr &= 240; // foreground = black + attr |= 112; // background = light grey + break; + + default: + if((attr&15)==8) // if foreground = dark grey + attr &= 247; // clear intensity bit + attr |= 7; // foreground = light grey + attr &= 143; // background = black + } + + return attr; // return converted attribute +} + + +// ------------------------------------------------------------------ +// Reverses the attribute given + +vattr revsattr(vattr attr) +{ + return (vattr)(((attr>>4)&0x07)|((attr<<4)&0x70)|(attr&0x80)|(attr&0x08)); +} + +#if !defined(__USE_NCURSES__) + + +// ------------------------------------------------------------------ + +#if defined(__UNIX__) +char* gvid_newattr(int& attr) { + + // 12345678901234567890 + // E[1;33;44mE[11m + static char newattr[20]; + *newattr = NUL; + if(attr != gvid_last_attr) { + if((attr & ~ACSET) != (gvid_last_attr & ~ACSET)) { + sprintf(newattr, "\033[%c;3%u;4%um", + vatr2ansin(attr) ? '1' : '0', + vatr2ansfg(attr), + vatr2ansbg(attr) + ); + } + if((attr & ACSET) != (gvid_last_attr & ACSET)) + strcat(newattr, (attr & ACSET) ? gvid_acs_enable : gvid_acs_disable); + gvid_last_attr = attr; + } + + return newattr; +} +#endif + + +// ------------------------------------------------------------------ +// OS/2 Vio* wrappers for prevent 16-bit segment overrun + +#if defined(__OS2__) + +#ifndef _THUNK_PTR_SIZE_OK +#define _THUNK_PTR_SIZE_OK(ptr,size) (((ULONG)(ptr) & ~0xffff) == (((ULONG)(ptr) + (size) - 1) & ~0xffff)) +#endif + +static USHORT VioReadCellStr_(PCH str, PUSHORT pcb, USHORT row, USHORT col, HVIO hvio) { + USHORT rc, cb = *pcb; + + if(_THUNK_PTR_SIZE_OK(str, cb)) + return VioReadCellStr(str, pcb, row, col, hvio); + PCH newstr = (PCH)throw_xmalloc(cb * 2); + if(_THUNK_PTR_SIZE_OK(newstr, cb)) { + rc = VioReadCellStr(newstr, pcb, row, col, hvio); + if(rc == 0) + memcpy(str, newstr, *pcb); + } + else { + rc = VioReadCellStr(newstr + cb, pcb, row, col, hvio); + if(rc == 0) + memcpy(str, newstr + cb, *pcb); + } + throw_xfree(newstr); + return rc; +} + + +static USHORT VioWrtCellStr_(PCCH str, USHORT cb, USHORT row, USHORT col, HVIO hvio) { + USHORT rc; + + if(_THUNK_PTR_SIZE_OK(str, cb )) + return VioWrtCellStr(str, cb, row, col, hvio); + PCH newstr = (PCH)throw_xmalloc(cb * 2); + if(_THUNK_PTR_SIZE_OK(newstr, cb)) { + memcpy(newstr, str, cb); + rc = VioWrtCellStr(newstr, cb, row, col, hvio); + } + else { + memcpy(newstr + cb, str, cb); + rc = VioWrtCellStr(newstr + cb, cb, row, col, hvio); + } + throw_xfree(newstr); + return rc; +} + + +static USHORT VioWrtCharStrAtt_(PCCH str, USHORT cb, USHORT row, USHORT col, PBYTE attr, HVIO hvio) { + USHORT rc; + + if(_THUNK_PTR_SIZE_OK(str, cb)) + return VioWrtCharStrAtt(str, cb, row, col, attr, hvio); + PCH newstr = (PCH)throw_xmalloc(cb * 2); + if(_THUNK_PTR_SIZE_OK(newstr, cb)) { + memcpy(newstr, str, cb); + rc = VioWrtCharStrAtt(newstr, cb, row, col, attr, hvio); + } + else { + memcpy(newstr + cb, str, cb); + rc = VioWrtCharStrAtt(newstr + cb, cb, row, col, attr, hvio); + } + throw_xfree(newstr); + return rc; +} + +#define VioReadCellStr VioReadCellStr_ +#define VioWrtCellStr VioWrtCellStr_ +#define VioWrtCharStrAtt VioWrtCharStrAtt_ + +#endif + +// ------------------------------------------------------------------ +// ncurses support functions + +#else // defined(__USE_NCURSES__) + +// ------------------------------------------------------------------ +// Compute our attributes from DOS attributes + +int gvid_attrcalc(int dosattr) { + + // DOS attrs: XRGBxrgb + // color pair definition: 00RGBrgb, with last 3 bits negated + int attr; + attr = COLOR_PAIR(((dosattr & 0x70) >> 1) | ((~dosattr) & 0x07)); + if(dosattr & 0x08) + attr |= A_BOLD; +// if(dosattr & 0x80) +// attr |= A_BLINK; + + return attr; +} + +// ------------------------------------------------------------------ +// Compute DOS attributes from our attributes + +int gvid_dosattrcalc(int ourattr) { + + int attr = 0; + attr = PAIR_NUMBER(ourattr); + attr = ((attr & 0x38) << 1) | ((~attr) & 0x07); + if(ourattr & A_BLINK) + attr |= 0x80; + if(ourattr & A_BOLD) + attr |= 0x08; + + return attr; +} + +// ------------------------------------------------------------------ +// Transform character < 32 into printable equivalent + + +chtype gvid_tcpr(vchar chr) { + + const chtype gvid_cpr[] = { + (chtype)' ', (chtype)'@', (chtype)'@', (chtype)'x', + (chtype) ACS_DIAMOND, (chtype)'x', (chtype)'x', ACS_BULLET, + ACS_BULLET, ACS_BULLET, ACS_BULLET, (chtype)'x', + (chtype)'x', (chtype)'x', (chtype)'x', ACS_LANTERN, + (chtype)ACS_RARROW, ACS_LARROW, (chtype)'x', (chtype)'!', + (chtype)'x', (chtype)'x', ACS_S1, (chtype)'x', + ACS_UARROW, ACS_DARROW, ACS_LARROW, (chtype)ACS_RARROW, + (chtype)'x', (chtype)'x', ACS_UARROW, ACS_DARROW + }; + + chtype ch = chr & A_CHARTEXT; + chtype at = chr & (~A_CHARTEXT); + + if(ch<' ') + return gvid_cpr[ch] | at; + else + return ch | at; +} + + +// ------------------------------------------------------------------ + +#endif // defined(__USE_NCURSES__) + + +// ------------------------------------------------------------------ +// Print character and attribute at specfied location + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +inline void _vputw(int row, int col, word chat) { + + _farpokew(_dos_ds, gdmaptr(col, row), chat); +} +#endif + + +void vputw(int row, int col, vatch chat) { + + #if defined(__USE_NCURSES__) + + mvaddch(row, col, chat); + refresh(); + + #elif defined(__MSDOS__) + + if(gvid->isdma()) { + _vputw(row, col, chat); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + cpu.ah(2); + cpu.bh(0); + cpu.dh((byte)row); + cpu.dl((byte)col); + cpu.genint(0x10); + cpu.ah(9); + cpu.al(vgchar(chat)); + cpu.bh(0); + cpu.bl(vgattr(chat)); + cpu.cx(1); + cpu.genint(0x10); + } + + #elif defined(__OS2__) + + VioWrtNCell((BYTE *)&chat, 1, (USHORT)row, (USHORT)col, 0); + + #elif defined(__WIN32__) + + const COORD coord = {0, 0}; + const COORD size = {1, 1}; + SMALL_RECT rect; + + rect.Top = row; + rect.Left = col; + rect.Bottom = row+size.Y-1; + rect.Right = col+size.X-1; + if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT) { + chat.Char.UnicodeChar = gvid_tcpr(vgchar(chat)); + WriteConsoleOutputW(gvid_hout, &chat, size, coord, &rect); + } + else + WriteConsoleOutputA(gvid_hout, &chat, size, coord, &rect); + + #elif defined(__UNIX__) + + char chr = vgchar(chat); + int atr = vgattr(chat); + char* color = gvid_newattr(atr); + + gvid_cvtstr(&chat, 1); + _vputw(row, col, chat); + + gvid_printf("\033[%u;%uH%s%c", row+1, col+1, color, chr); + + #endif +} + + +// ------------------------------------------------------------------ +// Print attrib/char buffer at specfied location + +void vputws(int row, int col, vatch* buf, uint len) { + + #if defined(__USE_NCURSES__) + + move(row, col); + for(int counter = 0; counter < len; counter++) + addch(buf[counter]); + refresh(); + + #elif defined(__MSDOS__) + + if(gvid->isdma()) { + gdmacpy(_dos_ds, (gdma)gdmaptr(col, row), _my_ds(), (gdma)buf, len*sizeof(word)); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + byte* p = (byte*)buf; + for(uint n=0; nisdma()) { + _vputw(row, col, vcatch(chr, atr)); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + cpu.ah(2); + cpu.bh(0); + cpu.dh((byte)row); + cpu.dl((byte)col); + cpu.genint(0x10); + cpu.ah(9); + cpu.al(chr); + cpu.bh(0); + cpu.bl((byte)atr); + cpu.cx(1); + cpu.genint(0x10); + } + + #elif defined(__OS2__) || defined(__WIN32__) + + vputw(row, col, vcatch(chr, atr)); + + #elif defined(__UNIX__) + + char* color = gvid_newattr(atr); + gvid_cvtstr(&chr, 1); + _vputw(row, col, vcatch(chr, atr)); + + gvid_printf("\033[%u;%uH%s%c", row+1, col+1, color, chr); + + #endif +} + + +// ------------------------------------------------------------------ +// Print string with attribute at specfied location + +void vputvs(int row, int col, vattr atr, const vchar* str) { + + #if defined(__USE_NCURSES__) + + uint counter; + int attr = gvid_attrcalc(atr); + move(row, col); + for(counter = 0; str[counter] != 0; counter++) + addch(gvid_tcpr(str[counter]) | attr); + refresh(); + + #else + + vputs(row, col, atr, str); + + #endif +} + + +// ------------------------------------------------------------------ +// Print string with attribute at specfied location + +void vputs_box(int row, int col, vattr atr, const char* str) { +#if defined(__USE_NCURSES__) + uint counter; + int len = strlen(str); + int attr = gvid_attrcalc(atr); + move(row, col); + for(counter = 0; counter < len; counter++) + addch(gvid_tcpr(gvid_boxcvtc(str[counter])) | attr); + refresh(); +#else + vputs(row, col, atr, str); +#endif +} + +void vputs(int row, int col, vattr atr, const char* str) { + + #if defined(__USE_NCURSES__) + + uint counter; + int len = strlen(str); + int attr = gvid_attrcalc(atr); + move(row, col); + for(counter = 0; counter < len; counter++) + addch(gvid_tcpr(str[counter]) | attr); + refresh(); + + #elif defined(__MSDOS__) + + if(gvid->isdma()) { + gdma p = gdmaptr(col, row); + _farsetsel(_dos_ds); + while(*str) { + _farnspokew(p, vcatch(*str++, atr)); + p += ATTRSIZE; + } + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + for(const char* q=str; *q; q++) { + // Write as fast as possible on XT bios... + cpu.ah(2); + cpu.bh(0); + cpu.dh((byte)row); + cpu.dl((byte)(col++)); + cpu.genint(0x10); + cpu.ah(9); + cpu.al(*q); + cpu.bh(0); + cpu.bl((byte)atr); + cpu.cx(1); + cpu.genint(0x10); + } + } + + #elif defined(__OS2__) + + VioWrtCharStrAtt((PCCH)str, (USHORT)strlen(str), (USHORT)row, (USHORT)col, (PBYTE)&atr, 0); + + #elif defined(__WIN32__) + + int i; + + for(i = 0; *str && (i < gvid->numcols); i++) + gvid->bufwrd[i] = vcatch(*str++, atr); + if(i) + vputws(row, col, gvid->bufwrd, i); + + #elif defined(__UNIX__) + + char buf[1024]; + strcpy(buf, str); + char* color = gvid_newattr(atr); + gvid_cvtstr(buf, strlen(buf)); + gdma p = gdmaptr(col, row); + _farsetsel(_dos_ds); + while(*str) { + _farnspokew(p, vcatch(*str++, atr)); + p += ATTRSIZE; + } + + gvid_printf("\033[%u;%uH%s%s", row+1, col+1, color, buf); + + #endif +} + + +// ------------------------------------------------------------------ +// Print string with attribute at specfied location + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +static void _vputns(int row, int col, int atr, const char* str, uint width) { + + char fillchar = ' '; + + gdma p = gdmaptr(col, row); + _farsetsel(_dos_ds); + while(width--) { + _farnspokew(p, (atr << 8) | (*str ? *str++ : fillchar)); + p += ATTRSIZE; + } +} +#endif + + +// ------------------------------------------------------------------ +// Print string with attribute at specfied location + +void vputns(int row, int col, vattr atr, const char* str, uint width) { + + char fillchar = ' '; + + #if defined(__USE_NCURSES__) + + uint counter; + int len = strlen(str); + int attr = gvid_attrcalc(atr); + move(row, col); + for(counter = 0; counter < width; counter++) { + if(counterisdma()) { + _vputns(row, col, atr, str, width); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + while(width--) { + // Write as fast as possible on XT bios... + cpu.ah(2); + cpu.bh(0); + cpu.dh((byte)row); + cpu.dl((byte)(col++)); + cpu.genint(0x10); + cpu.ah(9); + cpu.al(*str ? *str++ : fillchar); + cpu.bh(0); + cpu.bl((byte)atr); + cpu.cx(1); + cpu.genint(0x10); + } + } + + #elif defined(__OS2__) + + uint len = strlen(str); + + VioWrtCharStrAtt((PCCH)str, (USHORT)minimum_of_two(len,width), (USHORT)row, (USHORT)col, (PBYTE)&atr, 0); + + if(width > len) { + vatch filler = vcatch(fillchar, atr); + VioWrtNCell((BYTE *)&filler, (USHORT)(width-len), (USHORT)row, (USHORT)(col+len), 0); + } + + #elif defined(__WIN32__) + + int i; + + if (width > gvid->numcols) + width = gvid->numcols; + + for(i = 0; (i < width) and *str; i++) + gvid->bufwrd[i] = vcatch(*str++, atr); + vatch filler = vcatch(fillchar, atr); + for(; i < width; i++) + gvid->bufwrd[i] = filler; + vputws(row, col, gvid->bufwrd, width); + + #elif defined(__UNIX__) + + char* color = gvid_newattr(atr); + + uint len = strlen(str); + uint min_len = minimum_of_two(len, width); + char buf[1024]; + strcpy(buf, str); + gvid_cvtstr(buf, len); + + _vputns(row, col, atr, buf, width); + + char fillbuf[256]; + if(width > len) { + memset(fillbuf, fillchar, width-len); + fillbuf[width-len] = NUL; + } + else { + *fillbuf = NUL; + } + + gvid_printf("\033[%u;%uH%s%*.*s%s", row+1, col+1, color, + min_len, min_len, buf, fillbuf + ); + + #endif +} + + +// ------------------------------------------------------------------ +// Print horizontal line of character and attribute + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +void _vputx(int row, int col, int atr, char chr, uint len) { + + gdma p = gdmaptr(col, row); + word tmp = vcatch(chr, atr); + _farsetsel(_dos_ds); + for(uint n=0; nisdma()) { + _vputx(row, col, atr, chr, len); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + cpu.ah(2); + cpu.bh(0); + cpu.dh((byte)row); + cpu.dl((byte)col); + cpu.genint(0x10); + cpu.ah(9); + cpu.al(chr); + cpu.bh(0); + cpu.bl((byte)atr); + cpu.cx((word)len); + cpu.genint(0x10); + } + + #elif defined(__OS2__) + + vatch filler = vcatch(chr, atr); + VioWrtNCell((BYTE *)&filler, (USHORT)len, (USHORT)row, (USHORT)col, 0); + + #elif defined(__WIN32__) + + if (len > gvid->numcols) + len = gvid->numcols; + + vatch filler = vcatch(chr, atr); + for(int i = 0; i < len; i++) + gvid->bufwrd[i] = filler; + vputws(row, col, gvid->bufwrd, len); + + #elif defined(__UNIX__) + + char buf[256]; + char* color = gvid_newattr(atr); + gvid_cvtchr(chr); + _vputx(row, col, atr, chr, len); + memset(buf, chr, len); + buf[len] = NUL; + gvid_printf("\033[%u;%uH%s%s", row+1, col+1, color, buf); + + #endif +} + + +// ------------------------------------------------------------------ +// Print vertical line of character and attribute + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +inline void _vputy(int row, int col, int atr, char chr, uint len) { + + gdma p = gdmaptr(col, row); + word tmp = vcatch(chr, atr); + _farsetsel(_dos_ds); + for(uint n=0; nnumcols; + } +} +#endif + + +// ------------------------------------------------------------------ +// Print vertical line of character and attribute + +void vputy(int row, int col, vattr atr, vchar chr, uint len) { + + #if defined(__USE_NCURSES__) + + mvvline(row, col, vcatch(gvid_tcpr(chr), atr), len); + refresh(); + + #elif defined(__MSDOS__) + + if(gvid->isdma()) { + _vputy(row, col, atr, chr, len); + } + else if(gvid->isbios() or gvid->iscga()) { + for(uint n=0; nnumcols-1) { + sprintf(p, "\033[%u;%uH", row+n+2, col+1); + p += strlen(p); + } + else { + strcpy(p, "\033[D\033[B"); + p += 6; + } + } + *p++ = chr; + *p = NUL; + gvid_printf("%s", buf); + + #endif +} + + +// ------------------------------------------------------------------ +// Get character and attribute at cursor position + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +inline word _vgetw(int row, int col) { + + return _farpeekw(_dos_ds, gdmaptr(col, row)); +} +#endif + + +// ------------------------------------------------------------------ +// Get character and attribute at cursor position + +vatch vgetw(int row, int col) { + + #if defined(__USE_NCURSES__) + + return mvinch(row, col); + + #elif defined(__MSDOS__) + + if(gvid->isdma()) { + return _vgetw(row, col); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + cpu.ah(2); + cpu.bh(0); + cpu.dh((byte)row); + cpu.dl((byte)col); + cpu.genint(0x10); + cpu.ah(8); + cpu.bh(0); + cpu.genint(0x10); + return cpu.ax(); + } + return 0; + + #elif defined(__OS2__) + + vatch chat; + USHORT len=sizeof(chat); + + VioReadCellStr((BYTE *)&chat, &len, (USHORT)row, (USHORT)col, 0); + + return chat; + + #elif defined(__WIN32__) + + vatch chat; + const COORD coord = {0, 0}; + const COORD size = {1, 1}; + SMALL_RECT rect; + + rect.Top = row; + rect.Left = col; + rect.Bottom = row+size.Y-1; + rect.Right = col+size.X-1; + ReadConsoleOutput(gvid_hout, &chat, size, coord, &rect); + + return chat; + + #elif defined(__UNIX__) + + return _vgetw(row, col); + + #endif +} + + +// ------------------------------------------------------------------ +// Get character and attribute at cursor position + +void vgetc(int row, int col, vattr* atr, vchar* chr) { + + if((row < 0) or (row > gvid->numrows-1) or (col < 0) or (col > gvid->numcols-1)) { + *chr = ' '; + *atr = BLACK_|_BLACK; + } + else { + vatch tmp = vgetw(row, col); + + *chr = vgchar(tmp); + *atr = vgattr(tmp); + } +} + + +// ------------------------------------------------------------------ +// Scroll screen area + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +static void _vscroll(int srow, int scol, int erow, int ecol, int atr, int lines) { + + word empty = (atr << 8) | ' '; + if(lines > 0) { + while(lines--) { + int nrow = srow; + int l = ((ecol - scol) + 1); + gdma scrptr = gdmaptr(scol, srow); + while(nrow++ < erow) { + gdmacpy(_dos_ds, (gdma)scrptr, _dos_ds, (gdma)(scrptr+ATTRSIZE*gvid->numcols), l*sizeof(word)); + scrptr += ATTRSIZE*gvid->numcols; + } + _farsetsel(_dos_ds); + for(l *= ATTRSIZE; l>0;) { + l -= ATTRSIZE; + _farnspokew(scrptr+l, empty); + } + } + } + else { + while(lines++) { + int nrow = erow; + int l = ((ecol - scol) + 1); + gdma scrptr = gdmaptr(scol, erow); + while(nrow-- >= (srow + 1)) { + gdmacpy(_dos_ds, (gdma)scrptr, _dos_ds, (gdma)(scrptr-ATTRSIZE*gvid->numcols), l*sizeof(word)); + scrptr -= ATTRSIZE*gvid->numcols; + } + _farsetsel(_dos_ds); + for(l *= ATTRSIZE; l>0;) { + l -= ATTRSIZE; + _farnspokew(scrptr+l, empty); + } + } + } +} +#endif + + +// ------------------------------------------------------------------ +// Scroll screen area + +void vscroll(int srow, int scol, int erow, int ecol, vattr atr, int lines) { + + #if defined(__USE_NCURSES__) + + vatch filler = vcatch(' ', atr); + + // Currently implemented with vsave/vrestore + // Does anyone know a better solution? + + if(lines >= 0) { + if(lines <= 1 + erow - srow) { + vsavebuf *buf = vsave(srow + lines, scol, erow, ecol); + vrestore(buf, srow, scol, erow - lines, ecol); + throw_xfree(buf); + } + else + lines = 1 + erow - srow; + + for(int counter = 0; counter < lines; counter++) + mvhline(1 + erow + counter - lines, scol, filler, 1 + ecol - scol); + refresh(); + } + else { + lines*=-1; + if(lines <= 1 + erow - srow) { + vsavebuf *buf = vsave(srow, scol, erow - lines, ecol); + vrestore(buf, srow + lines, scol, erow, ecol); + throw_xfree(buf); + } + else + lines = 1 + erow - srow; + + for(int counter = 0; counter < lines; counter++) + mvhline(srow + counter, scol, filler, 1 + ecol - scol); + refresh(); + } + + #elif defined(__MSDOS__) + + if(gvid->isdma()) { + _vscroll(srow, scol, erow, ecol, atr, lines); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + cpu.ah((byte)(lines > 0 ? 6 : 7)); + cpu.al((byte)absolute(lines)); + cpu.bh((byte)atr); + cpu.ch((byte)srow); + cpu.cl((byte)scol); + cpu.dh((byte)erow); + cpu.dl((byte)ecol); + cpu.genint(0x10); + } + + #elif defined(__OS2__) + + vatch filler = vcatch(' ', atr); + + if(lines > 0) + VioScrollUp((USHORT)srow, (USHORT)scol, (USHORT)erow, (USHORT)ecol, (USHORT)lines, (BYTE *)&filler, 0); + else + VioScrollDn((USHORT)srow, (USHORT)scol, (USHORT)erow, (USHORT)ecol, (USHORT)-lines, (BYTE *)&filler, 0); + + #elif defined(__WIN32__) + + SMALL_RECT r; + COORD c = {scol, srow - lines}; + vatch filler = vcatch(' ', atr); + + r.Left = (SHORT)scol; + r.Top = (SHORT)srow; + r.Right = (SHORT)ecol; + r.Bottom = (SHORT)erow; + + ScrollConsoleScreenBuffer(gvid_hout, &r, &r, c, &filler); + + #elif defined(__UNIX__) + + _vscroll(srow, scol, erow, ecol, atr, lines); + + gdma ptr = gdmaptr(scol, srow); + int len = ecol-scol+1; + for(int nrow=srow; nrow<=erow; nrow++) { + vputansi(nrow, scol, ptr, len); + ptr += ATTRSIZE*gvid->numcols; + } + + #endif +} + + +// ------------------------------------------------------------------ +// Returns true if cursor invisible + +bool vcurhidden() { + + return __vcurhidden; +} + +// ------------------------------------------------------------------ +// Get cursor position + +void vposget(int* row, int* col) { + + #if defined(__USE_NCURSES__) + + getyx(stdscr, gvid->currow, gvid->curcol); + + #elif defined(__MSDOS__) + + i86 cpu; + cpu.ah(3); + cpu.bh(0); + cpu.genint(0x10); + gvid->currow = cpu.dh(); + gvid->curcol = cpu.dl(); + + #elif defined(__OS2__) + + USHORT _getrow, _getcol; + VioGetCurPos(&_getrow, &_getcol, 0); + gvid->currow = _getrow; + gvid->curcol = _getcol; + + #elif defined(__WIN32__) + + CONSOLE_SCREEN_BUFFER_INFO i; + GetConsoleScreenBufferInfo(gvid_hout, &i); + gvid->currow = i.dwCursorPosition.Y; + gvid->curcol = i.dwCursorPosition.X; + + #elif defined(__UNIX__) + + // Not available + + #endif + + *row = gvid->currow; + *col = gvid->curcol; +} + + +// ------------------------------------------------------------------ +// Set cursor position + +void vposset(int row, int col) { + + gvid->currow = row; + gvid->curcol = col; + + #if defined(__USE_NCURSES__) + + move(row, col); + refresh(); + + #elif defined(__MSDOS__) + + i86 cpu; + cpu.ah(2); + cpu.bh(0); + cpu.dh((byte)row); + cpu.dl((byte)col); + cpu.genint(0x10); + + #elif defined(__OS2__) + + VioSetCurPos((USHORT)row, (USHORT)col, 0); + + #elif defined(__WIN32__) + + // No need to set the cursor position if its not visible + // Strangely, this is a major speedup to screen-output + + if(__vcurhidden) + return; + + COORD c = {col, row}; + SetConsoleCursorPosition(gvid_hout, c); + + #elif defined(__UNIX__) + + gvid_printf("\x1B[%u;%uH", row+1, col+1); + + #endif +} + + +// ------------------------------------------------------------------ +// Clears the screen and homes the cursor + +void vclrscr() { + + vclrscr(vgattr(vgetw(gvid->currow, gvid->curcol))); +} + + +// ------------------------------------------------------------------ +// Clears the screen using given attribute and homes the cursor + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +static void _vclrscr(vattr atr) { + + int len = gvid->numrows * gvid->numcols; + + _vputx(0, 0, atr, ' ', len); +} +#endif + + + +// ------------------------------------------------------------------ +// Clears the screen using given attribute and homes the cursor + +void vclrscr(vattr atr) { + + #if defined(__USE_NCURSES__) + + clearok(stdscr, TRUE); + vatch filler = vcatch(' ', atr); + for(int row = 0; row < LINES; row++) + mvhline(row, 0, filler, COLS); + move(0, 0); + refresh(); + + #elif defined(__MSDOS__) + + if(gvid->isdma()) { + _vclrscr(atr); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + cpu.ax(0x0600); // clear screen by scrolling it + cpu.bh((byte)atr); + cpu.cx(0); + cpu.dh((byte)(gvid->numrows - 1)); + cpu.dl((byte)(gvid->numcols - 1)); + cpu.genint(0x10); + } + + #elif defined(__OS2__) + + vatch filler = vcatch(' ', atr); + VioScrollUp(0, 0, 0xFFFF, 0xFFFF, 0xFFFF, (BYTE *)&filler, 0); + + #elif defined(__WIN32__) + + COORD c = {0, 0}; + DWORD wr, len = gvid->numrows * gvid->numcols; + // Filling with space seems to work for both Unicode and regular functions + FillConsoleOutputCharacter(gvid_hout, ' ', len, c, &wr); + FillConsoleOutputAttribute(gvid_hout, (WORD)atr, len, c, &wr); + + #elif defined(__UNIX__) + + _vclrscr(atr); + + gvid_printf("%s\x1B[2J", gvid_newattr(atr)); + + #endif + + vposset(0,0); +} + + +// ------------------------------------------------------------------ +// Saves the current screen and returns pointer to buffer + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +static void _vsave(word* buf, int len1, int srow, int scol, int erow) { + + const int len2 = len1*sizeof(word); + gdma p = gdmaptr(scol, srow); + for(int nrow=srow; nrow<=erow; nrow++) { + gdmacpy(_my_ds(), (gdma)buf, _dos_ds, (gdma)p, len2); + p += ATTRSIZE*gvid->numcols; + buf += len1; + } +} +#endif + + +// ------------------------------------------------------------------ +// Saves the current screen and returns pointer to buffer + +vsavebuf* vsave(int srow, int scol, int erow, int ecol) { + + if(srow == -1) srow = 0; + if(scol == -1) scol = 0; + if(erow == -1) erow = gvid->numrows-1; + if(ecol == -1) ecol = gvid->numcols-1; + + vsavebuf* sbuf = (vsavebuf*)throw_xmalloc(sizeof(vsavebuf) + (erow - srow + 1) * (ecol - scol + 1) * sizeof(vatch)); + + if(sbuf) { + + vatch* buf = sbuf->data; + + sbuf->top = srow; + sbuf->left = scol; + sbuf->bottom = erow; + sbuf->right = ecol; + + #if defined(__USE_NCURSES__) + + for(int row=srow; row<=erow; row++) + for(int col=scol; col<=ecol; col++) + *buf++ = mvinch(row, col); + + #elif defined(__MSDOS__) + + int len1 = ecol-scol+1; + + if(gvid->isdma()) { + _vsave(buf, len1, srow, scol, erow); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + byte* p = (byte*)buf; + for(byte row=(byte)srow; row<=erow; row++) { + for(byte col=(byte)scol; col<=ecol; col++) { + cpu.ah(2); + cpu.bh(0); + cpu.dh(row); + cpu.dl(col); + cpu.genint(0x10); + cpu.ah(8); + cpu.bh(0); + cpu.genint(0x10); + *p++ = cpu.al(); + *p++ = cpu.ah(); + } + } + } + + #elif defined(__OS2__) + + int len1 = (int)(ecol-scol+1); + + #if defined(__BORLANDC__) + PCHAR16 ptr = (PCHAR16)buf; + #else + PCH ptr = (PCH)buf; + #endif + + USHORT len2 = (USHORT)(len1*sizeof(word)); + for(int nrow=srow; nrow<=erow; nrow++) { + VioReadCellStr(ptr, &len2, nrow, scol, 0); + ptr += len2; + } + + #elif defined(__WIN32__) + + const COORD coord = {0, 0}; + COORD size = {ecol-scol+1, erow-srow+1}; + SMALL_RECT r; + + // Set the source rectangle. + r.Top = srow; + r.Left = scol; + r.Bottom = erow; + r.Right = ecol; + + if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT) + ReadConsoleOutputW(gvid_hout, buf, size, coord, &r); + else + ReadConsoleOutputA(gvid_hout, buf, size, coord, &r); + + #elif defined(__UNIX__) + + int len1 = ecol-scol+1; + + _vsave(buf, len1, srow, scol, erow); + + #endif + } + + return sbuf; +} + + +// ------------------------------------------------------------------ +// Redraws a previously saved screen + +#if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__) +static void _vredraw(word* buf, int len1, int srow, int scol, int erow) { + + const int len2 = len1*sizeof(word); + gdma p = gdmaptr(scol, srow); + for(int nrow=srow; nrow<=erow; nrow++) { + gdmacpy(_dos_ds, (gdma)p, _my_ds(), (gdma)buf, len2); + p += ATTRSIZE*gvid->numcols; + buf += len1; + } +} +#endif + + +// ------------------------------------------------------------------ +// Redraws a previously saved screen + +void vrestore(vsavebuf* sbuf, int srow, int scol, int erow, int ecol) { + + if(srow != -1) sbuf->top = srow; + if(scol != -1) sbuf->left = scol; + if(erow != -1) sbuf->bottom = erow; + if(ecol != -1) sbuf->right = ecol; + + srow = sbuf->top; + scol = sbuf->left; + erow = sbuf->bottom; + ecol = sbuf->right; + + vatch *buf = sbuf->data; + + #if defined(__USE_NCURSES__) + + for(int row=srow; row<=erow; row++) + for(int col=scol; col<=ecol; col++) + mvaddch(row, col, *buf++); + + refresh(); + + #elif defined(__MSDOS__) + + int len1 = ecol-scol+1; + + if(gvid->isdma()) { + _vredraw(buf, len1, srow, scol, erow); + } + else if(gvid->isbios() or gvid->iscga()) { + i86 cpu; + byte* p = (byte*)buf; + for(byte row=(byte)srow; row<=erow; row++) { + for(byte col=(byte)scol; col<=ecol; col++) { + cpu.ah(2); + cpu.bh(0); + cpu.dh(row); + cpu.dl(col); + cpu.genint(0x10); + cpu.ah(9); + cpu.al(*p++); + cpu.bh(0); + cpu.bl(*p++); + cpu.cx(1); + cpu.genint(0x10); + } + } + } + + #elif defined(__OS2__) + + USHORT len1 = (USHORT)(ecol-scol+1); + USHORT len2 = (USHORT)(len1*sizeof(word)); + + #if defined(__BORLANDC__) + PCHAR16 ptr = (PCHAR16)buf; + #else + PCH ptr = (PCH)buf; + #endif + + for(USHORT nrow=srow; nrow<=erow; nrow++) { + VioWrtCellStr(ptr, len2, nrow, scol, 0); + ptr += len2; + } + + #elif defined(__WIN32__) + + const COORD coord = {0, 0}; + COORD size = {ecol-scol+1, erow-srow+1}; + SMALL_RECT r; + + // Set the source rectangle. + r.Top = srow; + r.Left = scol; + r.Bottom = erow; + r.Right = ecol; + + if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT) + WriteConsoleOutputW(gvid_hout, buf, size, coord, &r); + else + WriteConsoleOutputA(gvid_hout, buf, size, coord, &r); + + #elif defined(__UNIX__) + + int len1 = ecol-scol+1; + + _vredraw(buf, len1, srow, scol, erow); + + int atr = vgattr(*buf); + char* color = gvid_newattr(atr); + gvid_printf("%s", color); + + for(int nrow=srow; nrow<=erow; nrow++) { + vputansi(nrow, scol, buf, len1); + buf += len1; + } + + #endif +} + + +// ------------------------------------------------------------------ +// Sets the cursor shape/size + +void vcurset(int sline, int eline) { + + if(eline) { + gvid->curr.cursor.start = sline; + gvid->curr.cursor.end = eline; + __vcurhidden = false; + } + + #if defined(__USE_NCURSES__) + + if((sline == 0) and (eline == 0)) + curs_set(0); + else if((eline - sline) <= 4) + curs_set(1); + else + curs_set(2); + + #elif defined(__MSDOS__) + + if(eline == 0) { + int _dvhide = __gdvdetected ? 0x01 : 0x30; + sline = ((gvid->adapter>=V_HGC) and (gvid->adapter<=V_INCOLOR)) ? 0x3F : _dvhide; + } + + i86 cpu; + cpu.ah(1); + cpu.ch((byte)sline); + cpu.cl((byte)eline); + cpu.genint(0x10); + + #elif defined(__OS2__) + + VIOCURSORINFO vioci; + VioGetCurType(&vioci, 0); + vioci.yStart = (USHORT)sline; + vioci.cEnd = (USHORT)eline; + vioci.attr = (USHORT)((eline == 0) ? 0xFFFF : gvid->curr.color.textattr); + VioSetCurType(&vioci, 0); + + #elif defined(__WIN32__) + + CONSOLE_CURSOR_INFO cci; + + if(eline) + vposset(gvid->currow, gvid->curcol); + else /* Move cursor to bottom right corner (workaround of the win9x console bug) */ + vposset(gvid->numrows-1, gvid->numcols-1); + + cci.dwSize = (eline and sline) ? sline : 100; + cci.bVisible = make_bool(eline); + +// To hide cursor in w98 needs change byte sequnce in compiled gedcyg.exe: +// 0F 95 C0 89 45 FC +// B0 01 90 -- -- -- + + SetConsoleCursorInfo(gvid_hout, &cci); + + #elif defined(__UNIX__) + + gvid_printf("\033[?25%c", eline ? 'h' : 'l'); + + #endif +} + + +// ------------------------------------------------------------------ +// Hides the cursor + +void vcurhide() { + + if(not __vcurhidden) { + #if defined(__USE_NCURSES__) + curs_set(0); + #else + vcurset(0,0); + #endif + __vcurhidden = true; + } +} + + +// ------------------------------------------------------------------ +// Reveals the cursor + +void vcurshow() { + + if(__vcurhidden) { + vcurset(gvid->curr.cursor.start, gvid->curr.cursor.end); + __vcurhidden = false; + } +} + + +// ------------------------------------------------------------------ +// Sets a large cursor + +void vcurlarge() { + + #if defined(__USE_NCURSES__) + curs_set(2); + #else + vcurshow(); + + #if defined(__MSDOS__) + + switch(gvid->adapter) { + case V_CGA: + vcurset(1,7); + break; + case V_EGA: + if(gvid->numrows == 25) { + vcurset(1,7); + } + else { + word* p = (word*)0x0463; // video BIOS data area + outpw(*p,0x000A); // update cursor start register + outpw(*p,0x0A0B); // update cursor end register + } + break; + case V_VGA: + vcurset(1,7); + break; + default: // one of the monochrome cards + vcurset(1,12); + } + + #elif defined(__OS2__) + + vcurset(1, gvid->curr.screen.cheight-1); + + #elif defined(__WIN32__) + + vcurset(90, true); + + #endif + #endif +} + + +// ------------------------------------------------------------------ +// Sets a small cursor + +void vcursmall() { + + #if defined(__USE_NCURSES__) + curs_set(1); + #else + vcurshow(); + + #if defined(__MSDOS__) + + switch(gvid->adapter) { + case V_CGA: + vcurset(6,7); + break; + case V_EGA: + if(gvid->numrows == 25) { + vcurset(6,7); + } + else { + word* p = (word*)0x0463; // video BIOS data area + outpw(*p,0x060A); // update cursor start register + outpw(*p,0x000B); // update cursor end register + } + break; + case V_VGA: + vcurset(6,7); + break; + default: // one of the monochrome cards + vcurset(11,12); + } + + #elif defined(__OS2__) + + vcurset(gvid->curr.screen.cheight-2, gvid->curr.screen.cheight-1); + + #elif defined(__WIN32__) + + vcurset(13, true); + + #endif + #endif +} + + +// ------------------------------------------------------------------ +// Table of characters used to display boxes +// +// Access box table characters via: +// _box_table(boxtype, x) +// +// where: +// boxtype is the number of the box type you want to use (0 - 5) +// +// x will be one of the following: +// 0 - upper left corner +// 1 - upper horizontal line +// 2 - upper right corner +// 3 - left vertical line +// 4 - right vertical line +// 5 - lower left corner +// 6 - lower horizontal line +// 7 - lower right corner +// 8 - middle junction +// 9 - left vertical junction +// 10 - right vertical junction +// 11 - upper horizontal junction +// 12 - lower horizontal junction +// 13 - checkerboard +// 14 - solid block +// ------------------------------------------------------------------ + +#if !defined(__USE_NCURSES__) + +char* __box_table[] = { + + #if defined(__UNIX__) // This table will be actually patched at startup... + + ".-.||`-'+||-- #", // box type 0 Single border + ".-.||`-'+||-- #", // box type 1 Double border + ".-.||`-'+||-- #", // box type 2 Single top + ".-.||`-'+||-- #", // box type 3 Double top + " #", // box type 4 With empty border + ".-.||`-'+||-- #", // box type 5 No border at all + ".-.||`-'+||-- #", // box type 6 Blocky border + ".-.||`-'+||-- #", // box type 7 ASCII border + "lqkxxmqjntuwvaa", // box type 8 xterm single border + + #else + + "ÚÄ¿³³ÀÄÙÅôÂÁ°±", // box type 0 Single border + "ÉÍ»ººÈͼÎ̹ËÊ°±", // box type 1 Double border + "ÖÄ·ººÓĽ×ǶÒа±", // box type 2 Single top + "Õ͸³³Ô;ØƵÑÏ°±", // box type 3 Double top + " °±", // box type 4 With empty border + "ÚÄ¿³³ÀÄÙÅôÂÁ°±", // box type 5 No border at all + "ÜÜÜÝÞßßßÝÝÝÝÝ°±", // box type 6 Blocky border + ".-.||`-'+||--##", // box type 7 ASCII border + "lqkxxmqjntuwvaa", // box type 8 xterm single border + + #endif +}; +#else + +// ncurses ACS_nnn characters are usually computed at runtime, so +// we cannot use a static array + +chtype _box_table(int type, int c) { + + char asciiborder[] = ".-.||-'+||--##"; + + switch(type) { + case 4: + switch(c) { + case 13: + return ACS_BOARD; + case 14: + return ACS_BLOCK; + default: + return (chtype) ' '; + } + case 6: + switch(c) { + case 13: + return ACS_BOARD; + default: + return ACS_BLOCK; + } + case 7: + return (chtype) (asciiborder[c]); + default: + switch (c) { + case 0: + return ACS_ULCORNER; + case 1: + case 6: + return ACS_HLINE; + case 2: + return ACS_URCORNER; + case 3: + case 4: + return ACS_VLINE; + case 5: + return ACS_LLCORNER; + case 7: + return ACS_LRCORNER; + case 8: + return ACS_PLUS; + case 9: + return ACS_LTEE; + case 10: + return ACS_RTEE; + case 11: + return ACS_TTEE; + case 12: + return ACS_BTEE; + case 13: + return ACS_BOARD; + default: + return ACS_BLOCK; + } + } +} + +#endif + + +// ------------------------------------------------------------------ + +#if defined(__UNIX__) +void gvid_boxcvt(char* s) { + while(*s) + *s++ = (char)gvid_boxcvtc(*s); +} + +static uint32_t gvid_boxcvtc(char c) { + switch(c) { +#if 0 + case 'Ú': return _box_table(8, 0); + case 'Ä': return _box_table(8, 1); + case '¿': return _box_table(8, 2); + case '³': return _box_table(8, 4); + case 'À': return _box_table(8, 5); + case 'Ù': return _box_table(8, 7); + case 'Å': return _box_table(8, 8); + case 'Ã': return _box_table(8, 9); + case '´': return _box_table(8, 10); + case 'Â': return _box_table(8, 11); + case 'Á': return _box_table(8, 12); +#else + case 'Ú': return _box_table(0, 0); + case 'Ä': return _box_table(0, 1); + case '¿': return _box_table(0, 2); + case '³': return _box_table(0, 4); + case 'À': return _box_table(0, 5); + case 'Ù': return _box_table(0, 7); + case 'Å': return _box_table(0, 8); + case 'Ã': return _box_table(0, 9); + case '´': return _box_table(0, 10); + case 'Â': return _box_table(0, 11); + case 'Á': return _box_table(0, 12); + case 'É': return _box_table(1, 0); + case 'Í': return _box_table(1, 1); + case '»': return _box_table(1, 2); + case 'º': return _box_table(1, 4); + case 'È': return _box_table(1, 5); + case '¼': return _box_table(1, 7); + case 'Î': return _box_table(1, 8); + case 'Ì': return _box_table(1, 9); + case '¹': return _box_table(1, 10); + case 'Ë': return _box_table(1, 11); + case 'Ê': return _box_table(1, 12); +#endif + } + return c; +} +#endif + + +// ------------------------------------------------------------------ +// Draws a text box on the screen + +void vbox(int srow, int scol, int erow, int ecol, int box, vattr hiattr, vattr loattr) +{ + if (loattr == DEFATTR) + loattr = hiattr; + else if(loattr == -2) + loattr = (int)((hiattr & 0x08) ? (hiattr & 0xF7) : (hiattr | 0x08)); + + #if defined(__UNIX__) + hiattr |= ACSET; + loattr |= ACSET; + #endif + + vputc(srow, scol, hiattr, _box_table(box, 0)); // Top left corner + vputx(srow, scol+1, hiattr, _box_table(box, 1), ecol-scol-1); // Top border + vputc(srow, ecol, loattr, _box_table(box, 2)); // Top right corner + vputy(srow+1, scol, hiattr, _box_table(box, 3), erow-srow-1); // Left border + vputy(srow+1, ecol, loattr, _box_table(box, 4), erow-srow-1); // Right border + vputc(erow, scol, hiattr, _box_table(box, 5)); // Bottom left corner + vputx(erow, scol+1, loattr, _box_table(box, 6), ecol-scol-1); // Bottom border + vputc(erow, ecol, loattr, _box_table(box, 7)); // Bottom right corner +} + + +// ------------------------------------------------------------------ +// Fills an area of screen with a character & attribute + +void vfill(int srow, int scol, int erow, int ecol, vchar chr, vattr atr) { + + int width = ecol-scol+1; + for(int crow=srow; crow<=erow; crow++) + vputx(crow, scol, atr, chr, width); +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gvidinit.cpp b/goldlib/gcui/gvidinit.cpp new file mode 100644 index 0000000..12fab89 --- /dev/null +++ b/goldlib/gcui/gvidinit.cpp @@ -0,0 +1,1061 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// Copyright (C) 2000 Jacobo Tarrio +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Device-independent video functions. Initialise class GVid. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#if defined(__WATCOMC__) || defined(__DJGPP__) +#include +#endif +#include + +#if defined(__OS2__) +#define INCL_BASE +#include +#endif + +#if defined(__WIN32__) +#include +#endif + +#if !defined(__USE_NCURSES__) && defined(__UNIX__) +#include +#include +#include +#include +#endif + +#if defined(__DJGPP__) +#include +#include +#endif + + +// ------------------------------------------------------------------ +// Check if Borland C++ for OS/2 1.0 header has been fixed + +#if defined(__OS2__) && defined(__BORLANDC__) + #if __BORLANDC__ <= 0x400 + #ifndef BCOS2_BSESUB_FIXED + #error There is a bug in the BSESUB.H header. Please fix it. + // + // Add/change the following in BSESUB.H: + // + // #define BCOS2_BSESUB_FIXED + // APIRET16 APIENTRY16 VioGetState (PVOID16 pState, HVIO hvio); + // APIRET16 APIENTRY16 VioSetState (PVOID16 pState, HVIO hvio); + // + // Borland forgot this (was only PVOID) ^^ + // + #endif + #endif +#endif + + +// ------------------------------------------------------------------ +// Global video data + +GVid *gvid; + +#if defined(__USE_NCURSES__) + +// add statics here + +#elif defined(__UNIX__) + +int gvid_stdout = -1; +const char* gvid_acs_enable; +const char* gvid_acs_disable; + +void _vputx(int row, int col, int atr, char chr, uint len); +void gvid_printf(const char* fmt, ...) __attribute__ ((format (printf, 1, 2))); + +#elif defined(__WIN32__) + +HANDLE gvid_hout = INVALID_HANDLE_VALUE; + +#elif defined(__MSDOS__) + +int __gdvdetected = false; + +#endif + + +// ------------------------------------------------------------------ +// Video Class constructor + +GVid::GVid() { + + #ifdef __DJGPP__ + dmaptr = dmadir = 0; + #else + dmaptr = dmadir = NULL; + #endif + bufchr = NULL; + bufwrd = NULL; + bufansi = NULL; + + init(); +} + + +// ------------------------------------------------------------------ +// Video Class destructor + +GVid::~GVid() { + + #if defined(__USE_NCURSES__) + + attrset(A_NORMAL); + if(0 == (--curses_initialized)) + endwin(); + + #elif defined(__UNIX__) + + // "\033<" Enter ANSI mode + // "\033[?5l" Normal screen + // "\033[0m" Normal character attributes + + gvid_printf("\033<\033[?5l\033[0m"); + + #endif + #ifndef __DJGPP__ + if(dmaptr != dmadir) throw_xfree(dmaptr); + #endif + throw_xfree(bufwrd); + throw_xfree(bufchr); + throw_xfree(bufansi); +} + + +// ------------------------------------------------------------------ + +void GVid::init() { + + #if defined(__USE_NCURSES__) + // Both display and keyboard will be initialized at once + if(0 == (curses_initialized++)) { + initscr(); + raw(); + noecho(); + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + } + #endif + + // Detect video adapter + detectadapter(); + + // Detect original video information + detectinfo(&orig); + memcpy(&curr, &orig, sizeof(GVidInfo)); + + #if defined(__MSDOS__) + device = GVID_DMA; + #elif defined(__OS2__) + device = GVID_OS2; + #elif defined(__WIN32__) + device = GVID_W32; + #endif + + #if defined(__USE_NCURSES__) + dmaptr = dmadir = NULL; + #elif defined(__WATCOMC__) && defined(__386__) + dmaptr = dmadir = (gdma)(videoseg << 4); + #elif defined(__DJGPP__) + dmaptr = dmadir = ScreenPrimary; + #elif defined(__OS2__) || defined(__WIN32__) + dmaptr = dmadir = NULL; + #elif defined(__UNIX__) + dmaptr = (gdma)throw_xcalloc((orig.screen.rows+1)*orig.screen.columns, sizeof(word)); + dmadir = NULL; + #else + dmaptr = dmadir = (gdma)MK_FP(videoseg, 0); + #endif + + bufchr = NULL; + bufwrd = NULL; + bufansi = NULL; + + resetcurr(); +} + +// ------------------------------------------------------------------ +// Video adapter detect + +int GVid::detectadapter() { + + // Initialize to a valid value + adapter = GV_NONE; + + #if defined(__USE_NCURSES__) + + start_color(); + + setcolorpairs(); + + adapter = V_VGA; + + #elif defined(__MSDOS__) + + i86 cpu; + + // Get video mode + cpu.ah(V_GET_MODE); + cpu.genint(0x10); + int _got_mode = cpu.al(); + + // Check for PS/2 compatible video BIOS by calling the get + // video configuration function. If it exists, the video + // configuration code will be returned in BL. + + cpu.ax(0x1A00); + cpu.genint(0x10); + + if(cpu.al() == 0x1A) { + + switch(cpu.bl()) { + case 0x00: + adapter = GV_NONE; + break; + case 0x01: + adapter = V_MDA; + break; + case 0x02: + adapter = V_CGA; + break; + case 0x04: + adapter = V_EGA; + break; + case 0x05: + adapter = V_EGAMONO; + break; + case 0x07: + adapter = (_got_mode == 7) ? V_VGAMONO : V_VGA; + break; + case 0x08: + adapter = (_got_mode == 7) ? V_VGAMONO : V_VGA; + break; + case 0x0A: + case 0x0C: + adapter = V_MCGA; + break; + case 0x0B: + adapter = V_MCGAMONO; + break; + default: + adapter = V_VGA; // We hope it is VGA compatible! + } + } + else { + + // OK, we know that it's not a PS/2 BIOS, so check for an EGA. + // If an EGA is not present, BH will be unchanged on return. + + cpu.ah(0x12); + cpu.bl(0x10); + cpu.genint(0x10); + + if(cpu.bl() - 0x10) { + adapter = cpu.bh() ? V_EGAMONO : V_EGA; + } + else { + + // Now we know it's not an EGA. Get the BIOS equipment + // flag and test for CGA, MDA, or no video adapter. + + cpu.genint(0x11); + + switch(cpu.al() & 0x30) { + case 0x00: + adapter = (_got_mode == 7) ? V_VGAMONO : V_VGA; // EGA, VGA, or PGA + break; + case 0x10: + adapter = GV_NONE; // 40x25 color + break; + case 0x20: + adapter = V_CGA; // 80x25 color + break; + case 0x30: + adapter = V_MDA; // 80x25 monochrome + break; + } + } + } + + #ifndef __DJGPP__ + + // Set video segment + #if defined(__BORLANDC__) && defined(__DPMI32__) + videoseg = (word)((adapter & V_MONO) ? __SegB000 : __SegB800); + #else + videoseg = (word)((adapter & V_MONO) ? 0xB000 : 0xB800); + #endif + + // check for presence of DESQview by using the DOS Set + // System Date function and trying to set an invalid date + + cpu.ax(0x2B01); // DOS Set System Date + cpu.ch('D'); + cpu.cl('E'); + cpu.dh('S'); + cpu.dl('Q'); + cpu.genint(0x21); + + // if error, then DESQview not present + if(cpu.al() != 0xFF) { + + __gdvdetected = true; + + #if defined(__WATCOMC__) && defined(__386__) + memset(&RMI, 0, sizeof(RMI)); + RMI.EAX = 0x0000FE00; + RMI.ES = videoseg; + cpu.ax(0x0300); + cpu.bl(0x10); + cpu.bh(0); + cpu.cx(0); + cpu.es(FP_SEG(&RMI)); + cpu.edi(FP_OFF(&RMI)); + cpu.genint(0x31); + videoseg = RMI.ES; + #else + cpu.ah(0xFE); // DV get alternate video buffer + cpu.es(videoseg); + cpu.di(0x0000); + cpu.genint(0x10); + videoseg = cpu.es(); + #endif + } + + #endif // __DJGPP__ + + #elif defined(__OS2__) + + { + VIOCONFIGINFO vioconfiginfo; + memset(&vioconfiginfo, 0, sizeof(VIOCONFIGINFO)); + vioconfiginfo.cb = sizeof(VIOCONFIGINFO); + VioGetConfig(0, &vioconfiginfo, 0); + switch(vioconfiginfo.adapter) { + case DISPLAY_MONOCHROME: + adapter = V_MDA; + break; + case DISPLAY_CGA: + adapter = V_CGA; + break; + case DISPLAY_EGA: + adapter = V_EGA; + break; + case DISPLAY_VGA: + adapter = V_VGA; + break; + default: + adapter = V_VGA; // We hope it is VGA compatible! + } + if(vioconfiginfo.display == DISPLAY_MONOCHROME) + adapter |= V_MONO; + } + + #elif defined(__WIN32__) + + gvid_hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, + OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL); + + adapter = V_VGA; + + #elif defined(__linux__) + + for(int n=0; n<8; n++) + __box_table[n] = __box_table[8]; + + gvid_acs_enable = "\016"; + gvid_acs_disable = "\017"; + + gvid_stdout = fileno(stdout); + + adapter = V_VGA; + + #elif defined(__UNIX__) // code below should not be normally used... + + bool gvid_xterm = false; + const char* term = getenv("TERM"); + + if(term and strneql(term, "xterm", 5)) { + gvid_xterm = true; + for(int n=0; n<8; n++) + __box_table[n] = __box_table[8]; + } + + gvid_acs_enable = gvid_xterm ? "\033)0\033(B\016" : "\033[11m"; + gvid_acs_disable = gvid_xterm ? "\033(B\033)B\017" : "\033[10m"; + + gvid_stdout = fileno(stdout); + + adapter = V_VGA; + + #endif + + return adapter; +} + +void GVid::setcolorpairs(bool enabletransparent) { + #if defined(__USE_NCURSES__) + /* init colors */ + short mycolors[] = { COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, + COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE }; + + if(enabletransparent) + use_default_colors(); + for(int i = 1; i < 64 and i < COLOR_PAIRS; i++) { + short bg=mycolors[(i>>3)&0x07]; + init_pair(i, mycolors[(~i)&0x07], ((bg==COLOR_BLACK) && enabletransparent)?-1:bg); + } + #endif +} + +// ------------------------------------------------------------------ +// Video info detect + +void GVid::detectinfo(GVidInfo* _info) +{ + // Reset all original values + memset(_info, 0, sizeof(GVidInfo)); + + #if defined(__USE_NCURSES__) + + _info->screen.mode = 0; + _info->screen.rows = LINES; + _info->screen.columns = COLS; + getyx(stdscr, _info->cursor.row, _info->cursor.column); + _info->color.textattr = 7; + _info->cursor.start = 11; + _info->cursor.end = 12; + _info->cursor.attr = 7; + _info->color.intensity = 1; + _info->color.overscan = 0; + + #elif defined(__MSDOS__) + + i86 cpu; + + // Get video mode and number of columns + cpu.ah(V_GET_MODE); + cpu.genint(0x10); + _info->screen.mode = cpu.al(); + _info->screen.columns = cpu.ah(); + + // Get the number of screen rows + if(adapter >= V_EGA) { + cpu.ax(V_GET_FONT_INFO); + cpu.dx(0); + cpu.genint(0x10); + _info->screen.rows = cpu.dl() + ((adapter & V_EGA) ? 0 : 1); + if(_info->screen.rows == 24) // Normally nonsense + _info->screen.rows++; + //_info->screen.cheight = cpu.cx(); + _info->screen.cheight = 8; + _info->screen.cwidth = 8; + } + else { + _info->screen.rows = 25; + _info->screen.cheight = 8; + _info->screen.cwidth = 8; + } + + // Get character attribute under the cursor + cpu.ah(V_RD_CHAR_ATTR); + cpu.bh(0); + cpu.genint(0x10); + _info->color.textattr = cpu.ah(); + + // Get cursor position and form + cpu.ah(V_GET_CURSOR_POS); + cpu.bh(0); + cpu.genint(0x10); + _info->cursor.row = cpu.dh(); + _info->cursor.column = cpu.dl(); + _info->cursor.start = cpu.ch(); + _info->cursor.end = cpu.cl(); + _info->cursor.attr = (word)_info->color.textattr; + // Get overscan color + if(adapter & V_VGA) { + cpu.ax(0x1008); + cpu.bh(0xFF); + cpu.genint(0x10); + _info->color.overscan = cpu.bh(); + } + + // Get intensity state + { + // Check bit 5 at 0000:0465 + #if defined(__DJGPP__) + _info->color.intensity = (_farpeekb (_dos_ds, 0x465) & 0x20) ? 0 : 1; + #else + byte* _bptr = (byte*)0x0465; + _info->color.intensity = (*_bptr & 0x20) ? 0 : 1; + #endif + + } + + #elif defined(__OS2__) + + // Get video mode and number of rows and columns + { + VIOMODEINFO viomodeinfo; + memset(&viomodeinfo, 0, sizeof(VIOMODEINFO)); + viomodeinfo.cb = sizeof(VIOMODEINFO); + VioGetMode(&viomodeinfo, 0); + _info->screen.mode = viomodeinfo.fbType; + _info->screen.rows = viomodeinfo.row; + _info->screen.columns = viomodeinfo.col; + _info->screen.cheight = viomodeinfo.vres / viomodeinfo.row; + _info->screen.cwidth = viomodeinfo.hres / viomodeinfo.col; + } + + // Get cursor position and character attribute under the cursor + { + USHORT usRow, usColumn; + VioGetCurPos(&usRow, &usColumn, 0); + _info->cursor.row = usRow; + _info->cursor.column = usColumn; + BYTE chat[2]; + USHORT len = 2; + #if defined(__EMX__) + VioReadCellStr((PCH)chat, &len, usRow, usColumn, 0); + #else + VioReadCellStr((CHAR*)chat, &len, usRow, usColumn, 0); + #endif + _info->color.textattr = chat[1]; + } + + // Get cursor form + { + VIOCURSORINFO viocursorinfo; + memset(&viocursorinfo, 0, sizeof(VIOCURSORINFO)); + VioGetCurType(&viocursorinfo, 0); + _info->cursor.start = viocursorinfo.yStart; + _info->cursor.end = viocursorinfo.cEnd; + _info->cursor.attr = viocursorinfo.attr; + } + + // Get intensity state + { + VIOINTENSITY viointensity; + memset(&viointensity, 0, sizeof(VIOINTENSITY)); + viointensity.cb = sizeof(VIOINTENSITY); + viointensity.type = 0x0002; + VioGetState(&viointensity, 0); + _info->color.intensity = viointensity.fs ? 1 : 0; + } + + // Get overscan color + { + VIOOVERSCAN viooverscan; + memset(&viooverscan, 0, sizeof(VIOOVERSCAN)); + viooverscan.cb = sizeof(VIOOVERSCAN); + viooverscan.type = 0x0001; + VioGetState(&viooverscan, 0); + _info->color.overscan = (int)viooverscan.color; + } + + #elif defined(__WIN32__) + + // Get video mode and number of rows and columns + CONSOLE_SCREEN_BUFFER_INFO csbi; + int result = GetConsoleScreenBufferInfo(gvid_hout, &csbi); + assert(result != 0); + + _info->screen.mode = 0; + _info->screen.rows = csbi.dwSize.Y; + _info->screen.columns = csbi.dwSize.X; + + // Get cursor position and character attribute under the cursor + _info->cursor.row = csbi.dwCursorPosition.Y; + _info->cursor.column = csbi.dwCursorPosition.X; + _info->color.textattr = csbi.wAttributes; + + if(_info->screen.rows > 100) { + _info->screen.rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + _info->screen.columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; + _info->cursor.row = csbi.dwCursorPosition.Y - csbi.srWindow.Top + 1; + _info->cursor.column = csbi.dwCursorPosition.X - csbi.srWindow.Left + 1; + } + + // Get cursor form + CONSOLE_CURSOR_INFO cci; + GetConsoleCursorInfo(gvid_hout, &cci); + + _info->cursor.start = (int) 1; + _info->cursor.end = cci.bVisible ? (int) 15 : 0; + _info->cursor.attr = (word)(cci.bVisible ? 7 : 0); + + // Get intensity state + _info->color.intensity = 1; + + // Get overscan color + _info->color.overscan = 0; + + #elif defined(__UNIX__) + + int r = 0, c = 0; + + if(r <= 0) { + char *s = getenv("LINES"); + if(s) { + //printf("getenv(\"LINES\") = %s\n", s); + r = atoi(s); + } + } + + if(c <= 0) { + char *s = getenv("COLUMNS"); + if(s) { + //printf("getenv(\"COLUMNS\") = %s\n", s); + c = atoi(s); + } + } + + //printf("init1: c=%i, r=%i\n", c, r); + + #if defined(TIOCGSIZE) + if(r <= 0 or c <= 0) { + struct ttysize sz; + + do { + if((ioctl(1,TIOCGSIZE,&sz) == 0) or (ioctl(0, TIOCGSIZE, &sz) == 0) or (ioctl(2, TIOCGSIZE, &sz) == 0)) { + c = (int)sz.ts_cols; + r = (int)sz.ts_lines; + break; + } + } while(errno == EINTR); + } + //printf("init2: c=%i, r=%i\n", c, r); + #elif defined(TIOCGWINSZ) + if(r <= 0 or c <= 0) { + struct winsize wind_struct; + + do { + if((ioctl(1,TIOCGWINSZ,&wind_struct) == 0) or (ioctl(0, TIOCGWINSZ, &wind_struct) == 0) or (ioctl(2, TIOCGWINSZ, &wind_struct) == 0)) { + c = (int)wind_struct.ws_col; + r = (int)wind_struct.ws_row; + break; + } + } while(errno == EINTR); + } + //printf("init3: c=%i, r=%i\n", c, r); + #endif + + + if((r <= 0) or (r > 200)) + r = 24; + if((c <= 0) or (c > 250)) + c = 80; + + //printf("init4: c=%i, r=%i\n", c, r); + + //*dmadir = 0; + + _info->screen.mode = 0; + _info->screen.rows = r; + _info->screen.columns = c; + _info->cursor.row = 0; + _info->cursor.column = 0; + _info->color.textattr = 7; + _info->cursor.start = 11; + _info->cursor.end = 12; + _info->cursor.attr = 7; + _info->color.intensity = 1; + _info->color.overscan = 0; + + #endif + + getpalette(_info->color.palette); +} + + +// ------------------------------------------------------------------ +// Reset current video info + +void GVid::resetcurr() { + + currow = curr.cursor.row; + curcol = curr.cursor.column; + + numrows = curr.screen.rows; + numcols = curr.screen.columns; + + throw_xfree(bufchr); + throw_xfree(bufwrd); + throw_xfree(bufansi); + + bufchr = (vchar*)throw_xcalloc(sizeof(vchar), numcols+1); + bufwrd = (vatch*)throw_xcalloc(sizeof(vatch), numcols+1); + bufansi = (vchar*)throw_xcalloc(sizeof(vchar), (11*numcols)+1); + + setdevice(device); +} + + +// ------------------------------------------------------------------ +// Sets video output device + +void GVid::setdevice(int _device) { + + device = _device; +} + + +// ------------------------------------------------------------------ +// Sets video mode + +void GVid::setmode(int _mode) { + + if(_mode) { + #if defined(__MSDOS__) + + i86 cpu; + cpu.ah(0x00); + cpu.al((byte)_mode); + cpu.genint(0x10); + + #endif + } + + detectinfo(&curr); + resetcurr(); +} + + +// ------------------------------------------------------------------ +// Sets screen rows + +void GVid::setrows(int _rows) { + + int origrows = curr.screen.rows; + + #if defined(__USE_NCURSES__) + + NW(_rows); + + #elif defined(__MSDOS__) + i86 cpu; + + // Set video mode 3 (80xNN) + if(curr.screen.mode != 3) { + cpu.ax(0x0003); + cpu.genint(0x10); + } + + if(adapter >= V_EGA) { + if((_rows == 28) and (adapter >= V_VGA)) { // vga-only + cpu.ax(0x1202); + cpu.bl(0x30); + cpu.genint(0x10); + cpu.ax(0x1111); + cpu.bl(0); + cpu.genint(0x10); + } + else if(_rows >= 43) { + cpu.ax(0x1112); // Load 8x8 character set + cpu.bl(0x00); + cpu.genint(0x10); + cpu.ax(0x1200); // Select alternate print-screen routine + cpu.bl(0x20); + cpu.genint(0x10); + if(adapter & V_EGA) { + // Disable cursor size emulation + byte* _bptr = (byte*)0x0487; + *_bptr |= (byte)0x01; + // Set cursor size + cpu.ah(0x01); + cpu.al((byte)orig.screen.mode); + cpu.cx(0x0600); + cpu.genint(0x10); + } + } + else { + if(adapter & V_EGA) { + // Enable cursor size emulation + byte* _bptr = (byte*)0x0487; + *_bptr &= (byte)0xFE; + } + // Set cursor size + cpu.ah(0x01); + cpu.al((byte)orig.screen.mode); + cpu.cx(0x0607); + cpu.genint(0x10); + } + } + + #elif defined(__OS2__) + + VIOMODEINFO viomodeinfo; + memset(&viomodeinfo, 0, sizeof(VIOMODEINFO)); + viomodeinfo.cb = sizeof(VIOMODEINFO); + VioGetMode(&viomodeinfo, 0); + viomodeinfo.row = (USHORT)_rows; + VioSetMode(&viomodeinfo, 0); + + #elif defined(__WIN32__) || defined(__UNIX__) + + NW(_rows); + + #endif + + if(origrows < _rows) + vfill(origrows, 0, _rows, 80, ' ', LGREY_|_BLACK); + + detectinfo(&curr); + resetcurr(); +} + + +// ------------------------------------------------------------------ +// Set the screen border (overscan) color + +void GVid::setoverscan(vattr _overscan) +{ + #if defined(__USE_NCURSES__) + + NW (_overscan); + + #elif defined(__MSDOS__) + + i86 cpu; + cpu.ah(0x0B); + cpu.bh(0x00); + cpu.bl((byte)_overscan); + cpu.genint(0x10); + + #elif defined(__OS2__) + + VIOOVERSCAN viooverscan; + memset(&viooverscan, 0, sizeof(VIOOVERSCAN)); + viooverscan.cb = sizeof(VIOOVERSCAN); + viooverscan.type = 0x0001; + VioGetState(&viooverscan, 0); + viooverscan.color = (BYTE)_overscan; + VioSetState(&viooverscan, 0); + + #elif defined(__WIN32__) || defined(__UNIX__) + + NW(_overscan); + + #endif +} + + +// ------------------------------------------------------------------ +// Set intensity/blinking state + +void GVid::setintensity(int _intensity) +{ + #if defined(__USE_NCURSES__) + + NW(_intensity); + + #elif defined(__MSDOS__) + + #ifdef __DJGPP__ + + if(_intensity) + intensevideo(); + else + blinkvideo(); + + #else + + if(adapter & V_CGA) { + word* _wptr = (word*)0x0463; + byte* _bptr = (byte*)0x0465; + uint port = *_wptr + 4; + uint reg = *_bptr; + if(_intensity) + reg &= 0xDF; + else + reg |= 0x20; + outp(port, reg); + } + else { + i86 cpu; + cpu.ax(0x1003); + cpu.bh(0x00); + cpu.bl((byte)(_intensity ? 0 : 1)); + cpu.genint(0x10); + } + + #endif // __DJGPP__ + + #elif defined(__OS2__) + + VIOINTENSITY viointensity; + memset(&viointensity, 0, sizeof(VIOINTENSITY)); + viointensity.cb = sizeof(VIOINTENSITY); + viointensity.fs = (USHORT)(_intensity ? 1 : 0); + viointensity.type = 0x0002; + VioSetState(&viointensity, 0); + + #elif defined(__WIN32__) || defined(__UNIX__) + + NW(_intensity); + + #endif +} + + +// ------------------------------------------------------------------ + +void GVid::getpalette(int* _palette) +{ + #if defined(__USE_NCURSES__) + + NW(_palette); + + #elif defined(__MSDOS__) + + // Get palette state + if(adapter & V_VGA) { + i86 cpu; + for(byte n=0; n<16; n++) { + cpu.ax(0x1007); // GET INDIVIDUAL PALETTE REGISTER + cpu.bh(0xFF); + cpu.bl(n); + cpu.genint(0x10); + _palette[n] = cpu.bh(); + } + } + else { + // Set to standard palette colors + for(byte n=0; n<16; n++) + _palette[n] = n + ((n > 7) ? 48 : 0); + } + + #elif defined(__OS2__) + + // Get palette state + BYTE viopalstate[38]; + PVIOPALSTATE pviopalstate; + memset(viopalstate, 0, sizeof(viopalstate)); + pviopalstate = (PVIOPALSTATE)viopalstate; + pviopalstate->cb = sizeof(viopalstate); + pviopalstate->type = 0; + pviopalstate->iFirst = 0; + VioGetState(pviopalstate, 0); + for(byte n=0; n<16; n++) + _palette[n] = pviopalstate->acolor[n]; + + #elif defined(__WIN32__) || defined(__UNIX__) + + NW(_palette); + + #endif +} + + +// ------------------------------------------------------------------ + +void GVid::setpalette(int* _palette) +{ + #if defined(__USE_NCURSES__) + + NW(_palette); + + #elif defined(__MSDOS__) + + if(adapter & (V_EGA|V_MCGA|V_VGA)) { + i86 cpu; + for(byte n=0; n<16; n++) { + if(_palette[n] != -1) { + cpu.ax(0x1000); + cpu.bl(n); + cpu.bh((byte)_palette[n]); + cpu.genint(0x10); + } + } + } + + #elif defined(__OS2__) + + BYTE viopalstate[38]; + PVIOPALSTATE pviopalstate; + memset(viopalstate, 0, sizeof(viopalstate)); + pviopalstate = (PVIOPALSTATE)viopalstate; + pviopalstate->cb = sizeof(viopalstate); + pviopalstate->type = 0; + pviopalstate->iFirst = 0; + VioGetState(pviopalstate, 0); + for(byte n=0; n<16; n++) + if(_palette[n] != -1) + pviopalstate->acolor[n] = (USHORT)_palette[n]; + VioSetState(pviopalstate, 0); + + #elif defined(__WIN32__) || defined(__UNIX__) + + NW(_palette); + + #endif +} + + +// ------------------------------------------------------------------ + +void GVid::restore_cursor() { + + vcurset(orig.cursor.start, orig.cursor.end); + vcurshow(); + vposset(orig.cursor.row-1, 0); +} + + +// ------------------------------------------------------------------ + +void GVid::resize_screen(int columns, int rows) { + + numcols = curr.screen.columns = columns; + numrows = curr.screen.rows = rows; + + bufchr = (vchar*)throw_xrealloc(bufchr, numcols+1); + bufwrd = (vatch*)throw_xrealloc(bufwrd, (numcols+1)*sizeof(vatch)); + bufansi = (vchar*)throw_xrealloc(bufansi, 1+(11*numcols)); + + #if defined(__UNIX__) && !defined(__USE_NCURSES__) && !defined(__DJGPP__) + dmaptr = (gdma)throw_xrealloc(dmaptr, (rows+1)*columns*sizeof(word)); + #endif +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinall.h b/goldlib/gcui/gwinall.h new file mode 100644 index 0000000..09770aa --- /dev/null +++ b/goldlib/gcui/gwinall.h @@ -0,0 +1,448 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// Copyright (C) 2000 Jacobo Tarrio +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Windowing functions. +// Based on CXL by Mike Smedley. +// ------------------------------------------------------------------ + +#ifndef __gwinall_h +#define __gwinall_h + + +// ------------------------------------------------------------------ + +#include +#include +#include +#include + + +// ------------------------------------------------------------------ +// Error codes returned from windowing functions + +#define W_NOERROR 0 // no error +#define W_ESCPRESS 1 // Escape key was pressed +#define W_ALLOCERR 2 // memory allocation error +#define W_NOTFOUND 3 // record not found +#define W_NOACTIVE 4 // no active window +#define W_INVCOORD 5 // invalid coordinates +#define W_INVFORMT 6 // invalid format string +#define W_NOINPDEF 7 // no input fields defined +#define W_STRLONG 8 // string too long for window +#define W_INVBTYPE 9 // invalid box type +#define W_NOBORDER 10 // no window border +#define W_NOHIDDEN 11 // no hidden windows +#define W_NOTHIDD 12 // window is not hidden +#define W_NOSELECT 13 // no selectable menu items +#define W_NOITMDEF 14 // no menu items defined +#define W_NOMNUEND 15 // no end of menu specified +#define W_NOMNUDEF 16 // no menu defined +#define W_NOMNUBEG 17 // no begin of menu specified +#define W_NOFRMDEF 18 // no form defined +#define W_NOFRMBEG 19 // no begin of form specified +#define W_NOHLPDEF 20 // no help record defined +#define W_HLPSTKOV 21 // help stack overflow +#define W_HLPSTKUN 22 // help stack underflow +#define W_DOSERROR 23 // DOS error +#define W_NOMATCH 24 // no files matched input filespec +#define W_INVTAGID 25 // invalid tag identifier + + +// ------------------------------------------------------------------ +// Window border identifiers + +#define TP_BORD 0 // top border +#define BT_BORD 1 // bottom border +#define LT_BORD 2 // left border +#define RT_BORD 3 // right border + + +// ------------------------------------------------------------------ +// Direction codes + +#define D_DOWN 0 +#define D_UP 1 +#define D_LEFT 2 +#define D_RIGHT 3 +#define SDOWN D_DOWN // scroll down +#define SUP D_UP // scroll up + + +// ------------------------------------------------------------------ +// Scrollbar orientation + +const int W_HORZ = 1; +const int W_VERT = 2; + + +// ------------------------------------------------------------------ +// Menu item record definition + +struct _item_t { + _item_t* prev; // pointer to previous record + _item_t* next; // pointer to next record + void* child; // pointer to submenu's record + const char* str; // address of selection string + const char* desc; // text description of menu option + VfvCP select; // address of selection function + VfvCP before; // address of "before" function + VfvCP after; // address of "after" function + gkey hotkey; // hot key to select function + int tagid; // tag identifier + int help; // help category number + int wrow; // start of text - window row + int wcol; // start of text - window column + char schar; // quick selection character + int fmask; // special feature mask + int dwhdl; // description window handle + int dwrow; // description window row + int dwcol; // description window column + vattr dattr; // description attribute + int redisp; // redisplay flag +}; + + +// ------------------------------------------------------------------ +// Window menu record definition + +struct _menu_t { + _menu_t* prev; // pointer to prev menu structure + _menu_t* next; // pointer to next menu structure + _menu_t* parent; // pointer to parent menu + _item_t* item; // pointer to head menu item + _item_t* citem; // pointer to current menu item + VfvCP open; // address of post-opening function + int tagcurr; // tag ID of item selection bar on + int usecurr; // will menu use current window? + int srow; // starting row of menu window + int scol; // starting column of menu window + int erow; // ending row of menu window + int ecol; // ending column of menu window + int btype; // menu window border type + vattr battr; // menu window "hi" border attribute + vattr loattr; // menu window "lo" border attribute + vattr sbattr; // menu window scrollbar attribute + vattr wattr; // menu window attribute + int menutype; // menu type mask + int barwidth; // width of menu bar or zero + int textpos; // offset of text from start of bar + vattr textattr; // attribute of menu text + vattr scharattr; // attribute of selection character + vattr noselattr; // non-selectable text attribute + vattr barattr; // attribute of selection bar + const char* title; // menu title string or NULL if no title + int titlepos; // position of menu title (TLEFT,TCENTER,TRIGHT) + vattr titleattr; // attribute of menu title + vattr shadattr; // shadow attribute or -1 if no shadow + int items; // number of items in menu + bool hotkey; +}; + + +// ------------------------------------------------------------------ +// Window input field definition + +struct _field_t { + _field_t* prev; // pointer to previous field + _field_t* next; // pointer to next field + char* str; // address of receiving string + char* buf; // address of temp receive string + const char* format; // input field format string + IfcpCP validate; // address of validation function + VfvCP before; // address of "before" function + VfvCP after; // address of "after" function + int help; // help category number + int lenbuf; // length of buffer + int lenfld; // length of screen input field + int lenfmt; // length of format string + int wrow; // start of input - window row + int wcol; // start of input - window column + int mode; // 0=init, 1=update, 2=cond update + int decpos; // decimal position (numeric) + int redisp; // redisplay flag + char fconv; // field conversion character +}; + + +// ------------------------------------------------------------------ +// Window data entry form definition + +typedef gkey (*KfipCP)(int*); + +struct _form_t { + KfipCP getkey; // pointer to alternate get func + _form_t* prev; // pointer to previous form record + _form_t* next; // pointer to next form record + _field_t* field; // pointer to head field record + _field_t* cfield; // pointer to current field record + gkey* termkey; // addr of int for terminating key + const char* pformat; // format string pointer + char* pbuf; // buffer string pointer + int cwrow; // current window row + int cwcol; // current window column + int decimal; // decimal field flag + int insert; // insert mode flag + int fieldattr; // field attribute + int textattr; // text attribute +}; + + +// ------------------------------------------------------------------ +// Structure of window records + +struct _wrec_t { + _wrec_t* prev; // pointer to previous window record + _wrec_t* next; // pointer to next window record + _form_t* form; // pointer to head form record + vsavebuf* wbuf; // address of window's buffer + vatch* wsbuf; // address of window shadow's buffer + const char* title; // address of window's title string + int whandle; // window's handle + int help; // help category number + int srow; // start row of window + int scol; // start column of window + int erow; // end row of window + int ecol; // end column of window + int btype; // window's box type + vattr wattr; // window's initial text attribute + vattr battr; // attribute of window's border + vattr loattr; // attribute of window's border + vattr sbattr; // attribute of window's scrollbar + int border; // has border? 0 = no, 1 = yes + int row; // window's current cursor row + int column; // window's current cursor column + vattr attr; // window's current text attribute + int tpos; // position of window's title + vattr tattr; // attribute of window's title + vattr wsattr; // attribute of window's shadow +}; + + +// ------------------------------------------------------------------ + +class _help_t; + + +// ------------------------------------------------------------------ +// Window information record + +class GWin { + +public: + + _wrec_t* active; // pointer to active window + _wrec_t* hidden; // pointer to head hidden window + _menu_t* menu; // pointer to head menu record + _menu_t* cmenu; // pointer to current menu record + _help_t* helptr; // pointer to help info record + int handle; // last handle given to a window + int help; // current help category + int werrno; // error num from last window func + int total; // total number of open windows + int mlevel; // system variable used in menus + int ilevel; // system variable used in menus + int esc; // check for Esc in input funcions? + int tabwidth; // window TTY output tab width + vchar fillch; // character to fill windows with + int style; // how to open the windows + +public: + + GWin(); + ~GWin(); + +}; + +extern GWin gwin; + + +// ------------------------------------------------------------------ +// Window open styles + +#define STYLE_NORMAL 0 +#define STYLE_EXPLODE 1 +#define STYLE_EXPLODENOISY 2 + + +// ------------------------------------------------------------------ +// Fmask definitions for wmenuitem() + +#define M_HASPD 1 // has pull-down menu attached +#define M_NOSEL 2 // is not selectable +#define M_CLOSE 4 // close menu after select func +#define M_CLALL 8 // close all menus when selected +#define M_CLOSB 16 // close menu before select func +#define M_SEPAR (32 + M_NOSEL) // item is separator + +// ------------------------------------------------------------------ +// Menutype definitions for wmenuend() + +#define M_HORZ 1 // horizontal menu +#define M_VERT 2 // vertical menu +#define M_OMNI 7 // omnidirectional menu +#define M_PD 8 // pull-down menu +#define M_NOQS 16 // disable quick selection +#define M_SAVE 32 // save last bar position + + +// ------------------------------------------------------------------ +// Special return codes from wmenuget() + +#define M_EXIT 32764 // exit menu +#define M_EXITALL 32765 // exit all menus +#define M_PREVPD 32766 // previous pull-down menu +#define M_NEXTPD 32767 // next pull-down menu + + +// ------------------------------------------------------------------ +// Window title position definitions for wtitle() + +#define TTOP 0 // Top border +#define TLEFT 1 // Left justified +#define TCENTER 2 // Centered +#define TRIGHT 3 // Right justified +#define TBOTTOM 4 // Bottom border + + +// ------------------------------------------------------------------ +// Values for the Proportional Bar + +#define PROP_PAGE 1 +#define PROP_BARGRAPH 2 + + +// ------------------------------------------------------------------ + +extern int wpickstr_tag; + + +// ------------------------------------------------------------------ +// Function prototypes + +int wactiv (int whandle); +int wactiv_ (int whandle); +int wborder (int btype); +int wbox (int wsrow, int wscol, int werow, int wecol, int btype, int attr); +int wcclear (vattr attr); +int wcenters (int wrow, vattr attr, const char* str); +int wchkbox (int wsrow, int wscol, int werow, int wecol); +int wchkcol (int wcol); +int wchkcoord (int wrow, int wcol); +int wchkrow (int wrow); +int wclose (); +int wcloseall (); +int wclreol (); +int wclreos (); +int wcopy (int nsrow, int nscol); +int wdelline (int wrow, int direc); +int wdrag (int direction); +int wdupc (char ch, int count); +int wfill (int wsrow, int wscol, int werow, int wecol, vchar ch, vattr attr); +_wrec_t* wfindrec (int whandle); +int wgotoxy (int wrow, int wcol); +int whandle (); +int whide (); +int whline (int wsrow, int wscol, int count, int btype, vattr attr); +int wmessage (const char* str, int border, int leftofs, vattr attr); +int wmove (int nsrow, int nscol); +int wopen (int srow, int scol, int erow, int ecol, int btype, vattr battr, vattr wattr, vattr sbattr = DEFATTR, vattr loattr = DEFATTR); +inline int wopen_ (int srow, int scol, int vlen, int hlen, int btype, vattr battr, vattr wattr, vattr sbattr = DEFATTR, vattr loattr = DEFATTR) { return wopen(srow, scol, srow+vlen-1, scol+hlen-1, btype, battr, wattr, sbattr, loattr); } +int wperror (const char* message); +bool wpickfile (int srow, int scol, int erow, int ecol, int btype, vattr bordattr, vattr winattr, vattr barattr, bool title, std::string &filespec, IfcpCP open, bool casesens=false); +int wpickstr (int srow, int scol, int erow, int ecol, int btype, vattr bordattr, vattr winattr, vattr barattr, gstrarray &strarr, int initelem, VfvCP open); +int wprintc (int wrow, int wcol, vattr attr, vchar ch); +int wprintf (const char* format, ...) __attribute__ ((format (printf, 1, 2))); +int wprintaf (int attr, const char* format, ...) __attribute__ ((format (printf, 2, 3))); +int wprintfs (int wrow, int wcol, vattr attr, const char* format, ...) __attribute__ ((format (printf, 4, 5))); +int wprints (int wrow, int wcol, vattr attr, const char* str); +int wprints_box (int wrow, int wcol, vattr attr, const char* str); +int wprintvs (int wrow, int wcol, vattr attr, const vchar* str); +int wprintns (int wrow, int wcol, vattr attr, const std::string &str, uint len, vchar fill=' ', vattr fill_attr = DEFATTR); +int wprintsf (int wrow, int wcol, vattr attr, const char* format, const char* str); +int wprintws (int wrow, int wcol, vatch* buf, uint len); +void wpropbar (int xx, int yy, long len, vattr attr, long pos, long size); +int wputc (vchar ch); +int wputs (const char* str); +int wputx (int wrow, int wcol, vattr attr, vchar chr, uint len); +int wputy (int wrow, int wcol, vattr attr, vchar chr, uint len); +int wreadcur (int* wrow, int* wcol); +int wscroll (int count, int direc); +void wscrollbar (int orientation, uint total, uint maxpos, uint pos, int sadd=0); +int wscrollbox (int wsrow, int wscol, int werow, int wecol, int count, int direction); +int wshadoff (); +int wshadow (vattr attr); +int wsize (int nerow, int necol); +int wslide (int nsrow, int nscol); +void wtextattr (vattr attr); +int wtitle (const char* str, int tpos, vattr tattr); +int wunhide (int whandle); +int wunlink (int w); +int wvline (int wsrow, int wscol, int count, int btype, vattr attr); +int wwprintc (int whandle, int wrow, int wcol, vattr attr, const vchar chr); +int wwprints (int whandle, int wrow, int wcol, vattr attr, const char* str); +int wwprintstr (int whandle, int wrow, int wcol, vattr attr, const char* str); + +int wmenubeg (int srow, int scol, int erow, int ecol, int btype, vattr battr, vattr wattr, VfvCP open, int menutype=M_VERT); +inline int wmenubeg_ (int srow, int scol, int vlen, int hlen, int btype, vattr battr, vattr wattr, VfvCP open, int menutype=M_VERT) { return wmenubeg(srow, scol, srow+vlen-1, scol+hlen-1, btype, battr, wattr, open, menutype); } +int wmenubegc (); +int wmenuend (int taginit, int menutype, int barwidth, int textpos, vattr textattr, vattr scharattr, vattr noselattr, vattr barattr); +int wmenuget (); +int wmenuiba (VfvCP before, VfvCP after); +int wmenuidsab (int tagid); +int wmenuienab (int tagid); +_item_t* wmenuifind (int tagid); +int wmenuinext (int tagid); +int wmenuitem (int wrow, int wcol, const char* str, char schar, int tagid, int fmask, VfvCP select, gkey hotkey, int help); +int wmenuitxt (int whdl, int wrow, int wcol, vattr attr, const char* str); + + +// ------------------------------------------------------------------ +// Inline functions + +inline void wtextattr(vattr attr) { gwin.active->attr = attr; } + +inline int wclear () { return wcclear(gwin.active->wattr); } +inline void wfillch (vchar a) { gwin.fillch=a; } +inline vchar wgetc (int wrow, int wcol) { return vgetc(gwin.active->srow+wrow+gwin.active->border,gwin.active->scol+wcol+gwin.active->border); } +inline int wisactiv (int a) { return a == gwin.active->whandle; } +inline int wsetesc (int a) { int t=gwin.esc; gwin.esc=a; return t; } +inline void wsetstyle (int a) { gwin.style = a; } +inline int wstyle () { return gwin.style; } +inline void wtabwidth (int a) { gwin.tabwidth = (a==0) ? 1 : a; } + +inline _field_t* winpfcurr () { return gwin.active->form->cfield; } + +inline _menu_t* wmenumcurr () { return gwin.cmenu; } +inline _item_t* wmenuicurr () { return wmenumcurr()->citem; } + +inline int wmenutitshad(const char* title, int pos, vattr attr, vattr shadattr) { gwin.cmenu->title=title; gwin.cmenu->titlepos=pos; gwin.cmenu->titleattr=attr; gwin.cmenu->shadattr=shadattr; return W_NOERROR; } + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinbase.cpp b/goldlib/gcui/gwinbase.cpp new file mode 100644 index 0000000..c817875 --- /dev/null +++ b/goldlib/gcui/gwinbase.cpp @@ -0,0 +1,2104 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// Copyright (C) 2000 Jacobo Tarrio +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Windowing kernel. +// Based on CXL by Mike Smedley. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include + + +// ------------------------------------------------------------------ +// Local optimizations + +#define GOLD_INLINE inline +#define GOLD_WCHK + + +// ------------------------------------------------------------------ + +static GOLD_INLINE int _wchkrow(int wrow) { + + return ((wrow<0) or (wrow>((gwin.active->erow-gwin.active->border)-(gwin.active->srow+gwin.active->border)))); +} + +static GOLD_INLINE int _wchkcol(int wcol) { + + return ((wcol<0) or (wcol>((gwin.active->ecol-gwin.active->border)-(gwin.active->scol+gwin.active->border)))); +} + +static GOLD_INLINE int _wchkcoord(int wrow, int wcol) { + + return (_wchkrow(wrow) or _wchkcol(wcol)); +} + + +// ------------------------------------------------------------------ +// Checks validity of given window row coordinate + +int wchkrow(int wrow) { + + return _wchkrow(wrow); +} + + +// ------------------------------------------------------------------ +// Checks validity of given window column coordinate + +int wchkcol(int wcol) { + + return _wchkcol(wcol); +} + + +// ------------------------------------------------------------------ +// Checks validity of given window coordinates + +int wchkcoord(int wrow, int wcol) { + + return _wchkcoord(wrow, wcol); +} + + +// ------------------------------------------------------------------ +// Checks for valid window box coordinates + +int wchkbox(int wsrow, int wscol, int werow, int wecol) { + + return (_wchkcoord(wsrow,wscol) or _wchkcoord(werow,wecol) or (wsrow>werow) or (wscol>wecol)); +} + + +// ------------------------------------------------------------------ +// Sets window cursor coordinates + +int wgotoxy(int wrow, int wcol) { + + // check for valid cursor coordinates + #ifdef GOLD_WCHK + if(wchkcoord(wrow,wcol)) + return gwin.werrno=W_INVCOORD; + #endif + + // calculate effective cursor coordinates and update window record + const int &row = gwin.active->row = gwin.active->srow + wrow + gwin.active->border; + const int &col = gwin.active->column = gwin.active->scol + wcol + gwin.active->border; + + // set cursor location + vposset(row,col); + + // return with no error + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Opens a window and makes it active + +int wopen(int srow, int scol, int erow, int ecol, int btype, vattr battr, vattr wattr, vattr sbattr, vattr loattr) { + + // check for valid box type + if(btype<0 or btype>7) { + gwin.werrno=W_INVBTYPE; + return 0; + } + + if (ecol >= gvid->numcols) + ecol = gvid->numcols - 1; + + // see if window is to have a border + int border = (btype==5) ? NO : YES; + + // check for valid coordinates + if(srow>(erow-border) or scol>(ecol-border)) { + gwin.werrno=W_INVCOORD; + return 0; + } + + // allocate memory for new record + _wrec_t* wrec = (_wrec_t*)throw_xmalloc(sizeof(_wrec_t)); + if(wrec==NULL) { + gwin.werrno=W_ALLOCERR; + return 0; + } + + // save affected area of screen + vsavebuf* wbuf = vsave(srow,scol,erow,ecol); + if(wbuf==NULL) { + throw_xrelease(wrec); + gwin.werrno=W_ALLOCERR; + return 0; + } + + // add new record to linked list + if(gwin.active!=NULL) + gwin.active->next=wrec; + wrec->prev=gwin.active; + wrec->next=NULL; + gwin.active=wrec; + + // draw and fill text box on screen + switch(gwin.style) { + case STYLE_NORMAL: + if(border) + vbox(srow,scol,erow,ecol,btype,battr,loattr); + vfill(srow+border,scol+border,erow-border,ecol-border,gwin.fillch,wattr); + break; + } + + // increment window handle counter + gwin.handle++; + + // save window info in window record + gwin.active->wbuf = wbuf; + gwin.active->whandle = gwin.handle; + gwin.active->srow = srow; + gwin.active->scol = scol; + gwin.active->erow = erow; + gwin.active->ecol = ecol; + gwin.active->btype = btype; + gwin.active->wattr = wattr; + gwin.active->battr = battr; + gwin.active->loattr = loattr; + gwin.active->sbattr = sbattr; + gwin.active->border = border; + gwin.active->row = srow+border; + gwin.active->column = scol+border; + gwin.active->attr = wattr; + gwin.active->title = NULL; + gwin.active->tpos = 0; + gwin.active->help = 0; + gwin.active->form = NULL; + gwin.active->wsbuf = NULL; + + // increment total number of open windows + gwin.total++; + + // initialize cursor location to window row 0 column 0 + wgotoxy(0,0); + + // return normally + gwin.werrno=W_NOERROR; + return gwin.handle; +} + + +// ------------------------------------------------------------------ +// Closes a window + +int wclose() { + + // check for active window + if(!gwin.total or !gwin.active) + return(gwin.werrno=W_NOACTIVE); + + // if window has a shadow, close shadow first + if(gwin.active->wsbuf!=NULL) + wshadoff(); + + // restore contents of and free memory held by window + vrestore(gwin.active->wbuf); + throw_xrelease(gwin.active->wbuf); + + // decrement total number of open windows + gwin.total--; + + // free memory held by window's record and update linked list + _wrec_t *wrec = gwin.active->prev; + throw_xrelease(gwin.active); + gwin.active=wrec; + if(gwin.active!=NULL) + gwin.active->next=NULL; + + // update cursor location and help category + if(gwin.active!=NULL) { + vposset(gwin.active->row,gwin.active->column); + if(gwin.active->help) + gwin.help=gwin.active->help; + } + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Closes all open windows + +int wcloseall() { + + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + while(gwin.total) + if(wclose()) + return gwin.werrno; + + // close hidden windows too + _wrec_t* prev; + while(gwin.hidden!=NULL) { + prev = gwin.hidden->prev; + throw_xfree(gwin.hidden->wbuf); + throw_xfree(gwin.hidden); + gwin.hidden = prev; + } + + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Gives active window a shadow + +int wshadow(vattr attr) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // see if window already has a shadow + if(gwin.active->wsbuf!=NULL) + return gwin.werrno=W_NOERROR; + + // get window coordinates from the window's record + const int &srow = gwin.active->srow; + const int &scol = gwin.active->scol; + const int &erow = gwin.active->erow; + const int &ecol = gwin.active->ecol; + + // allocate buffer to hold shadow's contents + vatch* wsbuf = (vatch*)throw_xmalloc((((erow-srow)*sizeof(vatch))+ecol-scol+1)*sizeof(vatch)); + + if(wsbuf == NULL) + return gwin.werrno=W_ALLOCERR; + + // start at upper right corner of shadow and work down + int crow = srow+1; + int ccol = ecol+1; + vatch* q = wsbuf; + + // draw shadow to right of window + while(crow<=erow) { + + // read current screen characters/attributes and save in shadow's buffer + vatch tmp[2]; + *q = vgetw(crow, ccol); +#if defined(__USE_NCURSES__) || !defined(__UNIX__) + tmp[0] = vsattr(*q, attr); +#else + tmp[0] = vsattr(' ', attr); +#endif + q++; + *q = vgetw(crow, ccol + 1); +#if defined(__USE_NCURSES__) || !defined(__UNIX__) + tmp[1] = vsattr(*q, attr); +#else + tmp[1] = vsattr(' ', attr); +#endif + q++; + + // write characters back to screen using shadow's attribute + vputws(crow++, ccol, tmp, 2); + } + + // start at lower left corner of shadow and work right + crow = erow+1; + ccol = scol+2; + int stop = ecol+2; + int len = stop - ccol + 1; + vatch* wptr = (vatch*)gvid->bufwrd; + + // draw bottom shadow + while(ccol<=stop) { + + // read attribs/chars and store in buffers + *q = vgetw(crow, ccol++); +#if defined(__USE_NCURSES__) || !defined(__UNIX__) + *wptr++ = vsattr(*q, attr); +#else + *wptr++ = vsattr(' ', attr); +#endif + q++; + } + + // display complete buffer + vputws(crow, scol+2, gvid->bufwrd, len); + + // save info in window's record + gwin.active->wsbuf = wsbuf; + gwin.active->wsattr = attr; + + // reset cursor + vposset(gwin.active->row,gwin.active->column); + + // return with no error + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Removes shadow from active window + +int wshadoff() { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // if window doesn't have a shadow, ignore request + if(gwin.active->wsbuf==NULL) + return gwin.werrno=W_NOERROR; + + // get window coordinates from the window's record + const int &srow = gwin.active->srow; + const int &scol = gwin.active->scol; + const int &erow = gwin.active->erow; + const int &ecol = gwin.active->ecol; + + // start at upper right corner of shadow and work down + int crow = srow+1; + int ccol = ecol+1; + vatch* q = gwin.active->wsbuf; + + // delete shadow to right of window + while(crow<=erow) { + vputw(crow, ccol, *q++); + vputw(crow++, ccol+1, *q++); + } + + // start at lower left corner of shadow and work right + crow = erow+1; + ccol = scol+2; + int stop = ecol+2; + + // delete bottom shadow + while(ccol<=stop) + vputw(crow,ccol++,*q++); + + // free memory held by shadow + throw_xrelease(gwin.active->wsbuf); + + // update window's record + gwin.active->wsattr = WHITE_|_WHITE; + + // return with no error + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Scrolls the active window up or down + +int wscroll(int count, int direction) { + + // check for window border + const int &border = gwin.active->border; + + vscroll( + gwin.active->srow + border, + gwin.active->scol + border, + gwin.active->erow - border, + gwin.active->ecol - ((border or (gwin.active->sbattr != DEFATTR)) ? 1 : 0), + gwin.active->wattr, + direction == SUP ? count : -count + ); + + // return with no error + return gwin.werrno = W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Scrolls a region of the active window up or down + +int wscrollbox(int wsrow, int wscol, int werow, int wecol, int count, int direction) { + + // check for window border + const int &border = gwin.active->border; + + vscroll( + gwin.active->srow+wsrow+border, + gwin.active->scol+wscol+border, + gwin.active->srow+werow+border, + gwin.active->scol+wecol+border, + gwin.active->wattr, + direction == SUP ? count : -count + ); + + // return with no error + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Displays a character inside active window + +int wputc(char ch) { + + int cwcol; + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // get coordinates from window's record + int crow = gwin.active->row; + int ccol = gwin.active->column; + const int &scol = gwin.active->scol; + const int &border = gwin.active->border; + + // test the input character for control characters + switch(ch) { + case '\n': + crow++; + case '\r': + ccol=scol+border; + break; + case '\b': + if(ccol==(scol+border)) { + ccol=gwin.active->ecol-border; + crow--; + if(crow<(gwin.active->srow+border)) + crow++; + } + else { + ccol--; + } + break; + case '\t': + cwcol=ccol-border-scol; + ccol+=(tabstop(cwcol,gwin.tabwidth)-cwcol); + break; + default: + vputc(crow, ccol++, gwin.active->attr, ch); + } + + // see if wrap-around is needed + if(ccol > (gwin.active->ecol-border)) { + ccol = scol+border; + crow++; + } + + // see if scroll is needed + if(crow > (gwin.active->erow-border)) { + wscroll(1,SUP); + crow--; + } + + // update window's record + gwin.active->row=crow; + gwin.active->column=ccol; + + // reset cursor position + vposset(crow,ccol); + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Reads current cursor location inside window + +int wreadcur(int* wrow, int* wcol) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // read effective cursor coordinates + int row,col; + vposget(&row,&col); + + // calculate window cursor coordinates + const int &border = gwin.active->border; + *wrow = row - gwin.active->srow - border; + *wcol = col - gwin.active->scol - border; + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Display a character specified number of times + +int wdupc(char ch, int count) { + + // check for active window + if(!gwin.total) + return(gwin.werrno=W_NOACTIVE); + + // display ch for count times + while(count--) + wputc(ch); + + // return with gwin.werrno set by wputc() + return(gwin.werrno); +} + + +// ------------------------------------------------------------------ +// Clears the active window in specified attribute + +int wcclear(vattr attr) { + + // check for active window + + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for window border + + const int &border = gwin.active->border; + + vfill( + gwin.active->srow+border, + gwin.active->scol+border, + gwin.active->erow-border, + gwin.active->ecol-border, + gwin.fillch, + attr + ); + + // home the cursor + + wgotoxy(0,0); + + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Clears from cursor postion to end of window's line + +int wclreol() { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // clear to end of window's line + const int &column = gwin.active->column; + vputx( + gwin.active->row, + column, + gwin.active->attr, + gwin.fillch, + gwin.active->ecol - gwin.active->border - column + 1 + ); + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Clears from cursor postion to end of window + +int wclreos() { + + int wrow, werow, wr, wc; + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // save current window row and column + wreadcur(&wr, &wc); + + wrow = wr; + werow = gwin.active->erow - gwin.active->srow - gwin.active->border; + wclreol(); + wrow++; + + while(wrow <= werow) { + wgotoxy(wrow,0); + wclreol(); + wrow++; + } + + // restore window row and column + wgotoxy(wr,wc); + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// This function will process an Escape sequence when encountered + +static const char* process_esc(const char* str) +{ + int wrow,wcol; + + const char *p = str; + for(; *p==ESC; p++) { + + vattr attr = gwin.active->attr; + + switch(*(++p)) { + + case '+': // increase text attribute + wtextattr(++attr); + break; + + case '-': // decrease text attribute + wtextattr(--attr); + break; + + case 'A': // change attribute + wtextattr(*++p); + break; + + case 'F': // change foreground attribute + wtextattr((int)((*++p & 0x07) | (attr & ~0x07))); + break; + + case 'B': // change background attribute + wtextattr((int)((*++p & 0x70) | (attr & ~0x70))); + break; + + case 'I': // toggle intensity bit + wtextattr((int)(attr ^ INTENSE)); + break; + + case 'L': // toggle blinking bit + wtextattr((int)(attr ^ BLINK)); + break; + + case 'X': // reverse attribute + wtextattr(revsattr(attr)); + break; + + case 'R': // set cursor row + wreadcur(&wrow,&wcol); + wgotoxy(*++p,wcol); + break; + + case 'C': // set cursor column + wreadcur(&wrow,&wcol); + wgotoxy(wrow,*++p); + break; + + case 'E': // erase + switch(*++p) { + case 'W': // erase window + wclear(); + break; + case 'S': // erase to end of window + wclreos(); + break; + case 'L': // erase to end of window's line + wclreol(); + break; + } + break; + + case 'D': // duplicate character + { + char ch = *++p; + wdupc(ch,*++p); + } + break; + + default: + p--; + } + } + + return --p; +} + + +// ------------------------------------------------------------------ +// Displays a string inside active window + +int wputs(const char* str) { + + int cwcol; + const char* q; + + // get effective coordinates from window's record + int &crow = gwin.active->row; + int &ccol = gwin.active->column; + const int &scol = gwin.active->scol; + const int &border = gwin.active->border; + + // do while not end of string + for(q=str; *q; q++) { + + // test the input character for control characters + switch(*q) { + case '\n': + crow++; + case '\r': + ccol=scol+border; + break; + case '\b': + if(ccol==(scol+border)) { + ccol=gwin.active->ecol-border; + crow--; + if(crow<(gwin.active->srow+border)) + crow++; + } + else { + ccol--; + } + break; + case '\t': + cwcol=ccol-border-scol; + ccol+=(tabstop(cwcol,gwin.tabwidth)-cwcol); + break; + case ESC: + q=process_esc(q); + break; + default: + vputc(crow, ccol++, gwin.active->attr, *q); + } + + // see if wrap-around is needed + if(ccol > (gwin.active->ecol-border)) { + ccol=scol+border; + crow++; + } + + // see if scroll is needed + if(crow > (gwin.active->erow-border)) { + wscroll(1,SUP); + crow--; + } + } + + // reset cursor position + vposset(crow,ccol); + + // return normally + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ +// Displays a character inside active window + +int wprintc(int wrow, int wcol, vattr atr, vchar chr) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid coordinates + #ifdef GOLD_WCHK + if(wchkcoord(wrow,wcol)) + return gwin.werrno=W_INVCOORD; + #endif + + vputc(wrow+gwin.active->srow+gwin.active->border, wcol+gwin.active->scol+gwin.active->border, atr, chr); + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Outputs a formatted string to active window + +int wprintf(const char* format, ...) { + + va_list argptr; + char buf[255]; + + // format string using specified parameters into buffer + va_start(argptr,format); // access argument list + int result = vsprintf(buf,format,argptr); // create string using argument list + va_end(argptr); // end access of argument list + + // display the created string + wputs(buf); + + return result; +} + + +// ------------------------------------------------------------------ +// Print a formatted string at a specific position and attribute + +int wprintfs(int wrow, int wcol, vattr attr, const char* format, ...) { + + va_list argptr; + char buf[256]; + + *buf = NUL; + va_start(argptr, format); + int result = vsprintf(buf, format, argptr); + va_end(argptr); + + wprints(wrow, wcol, attr, buf); + + return result; +} + + +// ------------------------------------------------------------------ +// Displays a string inside active window + +int wprints(int wrow, int wcol, vattr attr, const char* str) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid coordinates + #ifdef GOLD_WCHK + if(wchkcoord(wrow,wcol)) + return gwin.werrno=W_INVCOORD; + #endif + + const int &border = gwin.active->border; + vputs(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str); + return gwin.werrno=W_NOERROR; +} + +int wprints_box(int wrow, int wcol, vattr attr, const char* str) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid coordinates + #ifdef GOLD_WCHK + if(wchkcoord(wrow,wcol)) + return gwin.werrno=W_INVCOORD; + #endif + + const int &border = gwin.active->border; + vputs_box(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str); + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Displays a string inside active window + +int wprintvs(int wrow, int wcol, vattr attr, const vchar* str) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid coordinates + #ifdef GOLD_WCHK + if(wchkcoord(wrow,wcol)) + return gwin.werrno=W_INVCOORD; + #endif + + const int &border = gwin.active->border; + vputvs(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str); + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int wputx(int wrow, int wcol, vattr attr, vchar chr, uint len) { + + const int &border = gwin.active->border; + vputx(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,chr,len); + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int wputy(int wrow, int wcol, vattr attr, vchar chr, uint len) { + + const int &border = gwin.active->border; + vputy(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,chr,len); + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Displays a string inside active window + +int wprintns(int wrow, int wcol, vattr attr, const std::string &str, uint len, vchar fill, vattr fill_attr) +{ + char* istr = throw_xstrdup(str.c_str()); + char* ostr = istr; + char och = *ostr; + uint olen = strlen(istr); + if(len < olen) { + ostr += len; + och = *ostr; + *ostr = NUL; + } + int retval = wprints(wrow, wcol, attr, istr); + if(len < olen) + *ostr = och; + else if(len > olen) + retval = wputx(wrow, wcol+olen, (fill_attr != DEFATTR) ? fill_attr : attr, fill, len-olen); + throw_xfree(istr); + return retval; +} + + +// ------------------------------------------------------------------ +// Displays attrib/char buffer inside active window + +int wprintws(int wrow, int wcol, vatch* buf, uint len) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid coordinates + #ifdef GOLD_WCHK + if(wchkcoord(wrow,wcol)) + return gwin.werrno=W_INVCOORD; + #endif + + // see if window has border + const int &border = gwin.active->border; + + // calculate effective coordinates + int row = gwin.active->srow+wrow+border; + int col = gwin.active->scol+wcol+border; + + // display buffer + vputws(row, col, buf, len); + + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Returns address of record of given window handle + +_wrec_t* wfindrec(int whandle) { + + _wrec_t *wrec; + + // scan through linked list for record belonging to requested handle + + wrec = gwin.active; + while(wrec) { + if(whandle==wrec->whandle) + break; + wrec=wrec->prev; + } + + if(wrec == NULL) { + + // Search through the hidden windows + + wrec = gwin.hidden; + while(wrec) { + if(whandle==wrec->whandle) + break; + wrec=wrec->prev; + } + } + + // return address of found record + return wrec; +} + + +// ------------------------------------------------------------------ +// Hides active window + +int whide() { + + vsavebuf *p; + vattr shattr; + _wrec_t *temp; + + // check for active window + if(!gwin.total) + return(gwin.werrno=W_NOACTIVE); + + // save active window + p = vsave(gwin.active->srow,gwin.active->scol,gwin.active->erow,gwin.active->ecol); + + // check for/close window's shadow + if(gwin.active->wsbuf!=NULL) { + shattr = gwin.active->wsattr; + wshadoff(); + gwin.active->wsattr = shattr; + } + else { + gwin.active->wsattr = DEFATTR; + } + + // restore contents of active window's buffer + vrestore(gwin.active->wbuf); + throw_xfree(gwin.active->wbuf); + gwin.active->wbuf = p; + + // update visible window record linked list + temp = gwin.active; + gwin.active = gwin.active->prev; + if(gwin.active) + gwin.active->next = NULL; + gwin.total--; + + // update hidden window record linked list + if(gwin.hidden) + gwin.hidden->next = temp; + temp->prev = gwin.hidden; + temp->next = NULL; + gwin.hidden = temp; + + // update cursor location and help category + if(gwin.active) { + vposset(gwin.active->row,gwin.active->column); + if(gwin.active->help) + gwin.help = gwin.active->help; + } + + // return normally + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ +// Unhides a previously hidden window + +int wunhide(int whandle) { + + vsavebuf* p; + _wrec_t* found; + + // check pointer to hidden window linked list ; must not be NULL + if(gwin.hidden==NULL) + return gwin.werrno=W_NOHIDDEN; + + // check to see if input window handle == 0. if so, then + // that means to unhide the most recently hidden window. + if(!whandle) + whandle=gwin.hidden->whandle; + + // scan through linked list for record belonging to requested handle + found=gwin.hidden; + while(found!=NULL) { + if(whandle==found->whandle) + break; + found=found->prev; + } + + // was handle found in hidden window record linked list? + if(found==NULL) { + + // see if handle is in visible window record linked list + if(wfindrec(whandle)==NULL) + return gwin.werrno=W_NOTFOUND; + else + return gwin.werrno=W_NOTHIDD; + } + + // save area of screen where window is to unhide at + if((p=vsave(found->srow,found->scol,found->erow,found->ecol))==NULL) + return gwin.werrno=W_ALLOCERR; + + // restore contents of hidden window back to screen + vrestore(found->wbuf); + throw_xfree(found->wbuf); + found->wbuf=p; + + // update hidden window record linked list + if(found->prev!=NULL) + found->prev->next=found->next; + if(found->next==NULL) + gwin.hidden=found->prev; + else + found->next->prev=found->prev; + + // update visible window record linked list + if(gwin.active!=NULL) + gwin.active->next=found; + found->prev=gwin.active; + found->next=NULL; + gwin.active=found; + gwin.total++; + + // if window had a shadow before hiding, give it one again + if(gwin.active->wsattr != DEFATTR) + wshadow(gwin.active->wsattr); + + // update help category + if(gwin.active->help) + gwin.help=gwin.active->help; + + // reset cursor + vposset(gwin.active->row,gwin.active->column); + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Unlinks and frees a window from memory, but does not manipulate +// the screen at all + +int wunlink(int w) { + + _wrec_t *found, *prev, *next; + + // check to see if input window handle == 0. if + // so, then that means to unlink the active window. + if(!w) + w=gwin.active->whandle; + + // find address of window record for given window handle + if((found=wfindrec(w))==NULL) + return gwin.werrno=W_NOTFOUND; + + // free memory held by shadow's buffer (if shadow exists) + if(found->wsbuf!=NULL) + throw_xrelease(found->wsbuf); + + // free memory held by window's buffer + throw_xrelease(found->wbuf); + + // decrement total number of open windows + gwin.total--; + + // re-link list pointers around window record to remove + prev=found->prev; + next=found->next; + if(prev!=NULL) + prev->next=next; + if(next!=NULL) + next->prev=prev; + + // free memory held by window record + throw_xfree(found); + + // see if active window has changed + if(next==NULL) { + if(prev!=NULL) { + gwin.active=prev; + if(gwin.active->help) + gwin.help=gwin.active->help; + } + } + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Local variables + +static _wrec_t *__curr, *__found; +static int __crow, __ccol; +static vattr __gattr; +static const char* __p; + + +// ------------------------------------------------------------------ +// This function dectects if given window is blocking the current +// window or its shadow at specified coordinates + +static GOLD_INLINE int window_blocking() { + + return (__crow>=__curr->srow and __crow<=__curr->erow and __ccol>=__curr->scol and __ccol<=__curr->ecol) ? YES : NO; +} + + +// ------------------------------------------------------------------ +// This function detects if a given window's bottom shadow is +// blocking the current window or its shadow at specified coordinates + +static GOLD_INLINE int bshadow_blocking() { + + if(__crow==(__curr->erow+1)) + if((__ccol>=(__curr->scol+2)) and (__ccol<=(__curr->ecol+2))) + return YES; + else + return NO; + + return NO; +} + + +// ------------------------------------------------------------------ +// This function detects if a given window's right shadow is blocking +// the current window or its shadow at specified coordinates + +static GOLD_INLINE int rshadow_blocking() { + + if(__ccol==(__curr->ecol+1) or __ccol==(__curr->ecol+2)) + if((__crow>=(__curr->srow+1)) and (__crow<=__curr->erow)) + return YES; + else + return NO; + + return NO; +} + + +// ------------------------------------------------------------------ + +static GOLD_INLINE vatch* calc_window(_wrec_t *wrec) { + + return wrec->wbuf->data+((__crow-wrec->srow)*(wrec->ecol-wrec->scol+1))+(__ccol-wrec->scol); +} + + +// ------------------------------------------------------------------ + +static GOLD_INLINE vatch* calc_bshadow(_wrec_t *wrec) { + + return wrec->wsbuf+((((__crow-wrec->srow-1)*2)+(__ccol-wrec->scol-2))); +} + + +// ------------------------------------------------------------------ + +static GOLD_INLINE vatch* calc_rshadow(_wrec_t *wrec) { + + return wrec->wsbuf+((((__crow-wrec->srow-1)*2)+(__ccol-wrec->ecol-1))); +} + + +// ------------------------------------------------------------------ +// This function will exchange the contents of the applicable buffers + +static void swap_contents(vatch* pfound, vatch* pcurr, int shadow) { + + register _wrec_t *wptr; + register vatch temp, chat; + + // display character from current position in window to + // activate on the screen. if character is part of a + // shadow, reflect the character on the screen. + + temp = vgetw(__crow, __ccol); + + if(shadow&2) + *pcurr = vschar(*pcurr, vgchar(temp)); + chat = ((vgattr(temp) & BLINK) and shadow) ? vsattr(*pcurr, vgattr(*pcurr) | BLINK) : *pcurr; + vputw(__crow, __ccol, chat); + + // let window position directly above position + // to activate have the character that it holds + + *pcurr = *pfound; + + // if current character position to activate will + // activate over a shadow in another window + + if(shadow&1) { + + // resolve all shadows upwards + + wptr = __curr; + chat = vsattr(*pfound, __curr->wsattr); + + for(__curr=__curr->next;__curr!=NULL;__curr=__curr->next) { + + if(window_blocking()) { + *(calc_window(__curr)) = chat; + chat = temp; + break; + } + else { + if(bshadow_blocking()) + *(calc_bshadow(__curr)) = chat; + else { + if(rshadow_blocking()) + *(calc_rshadow(__curr)) = chat; + } + } + } + + temp = chat; + __curr = wptr; + } + + // let character position activated hold character + // that was on the screen in the same position + + *pfound = temp; +} + + +// ------------------------------------------------------------------ + +int wactiv(int whandle) { + + register int startcol, stopcol; + _wrec_t *prev, *next; + + // check for active window + + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // if window is already active, ignore request + + if(whandle==gwin.active->whandle) + return gwin.werrno=W_NOERROR; + + // find address of window's record + + __found=wfindrec(whandle); + if(__found==NULL) + return gwin.werrno=W_NOTFOUND; + + // check every character position in window to activate + + for(__crow=__found->srow;__crow<=__found->erow;__crow++) { + for(__ccol=__found->scol;__ccol<=__found->ecol;__ccol++) { + + // check all window records "above" window to activate + + for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) { + + // see if current position in window to activate + // is blocked by same position in test window + + if(window_blocking()) { + + // calculate buffer addresses and swap contents + + swap_contents(calc_window(__found),calc_window(__curr),0); + break; + } + + // see if test window has a shadow + + if(__curr->wsbuf!=NULL) { + + // see if shadow to the right of test window is + // blocking the current position of window to activate + + if(rshadow_blocking()) { + swap_contents(calc_window(__found),calc_rshadow(__curr),1); + break; + } + + // see if shadow to the bottom of test window is + // blocking the current position of window to activate + + if(bshadow_blocking()) { + swap_contents(calc_window(__found),calc_bshadow(__curr),1); + break; + } + } + } + } + } + + // if window to activate has a shadow, then check + // every character position in the shadow to see + // if it is blocked by another window or window shadow + + if(__found->wsbuf!=NULL) { + + // search the right shadow of window to activiate + + startcol=__found->ecol+1; + stopcol=startcol+1; + for(__crow=__found->srow+1;__crow<=__found->erow;__crow++) { + for(__ccol=startcol;__ccol<=stopcol;__ccol++) { + + // check all window records "above" shadow to activate + + for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) { + + // see if current position in shadow to activate + // is blocked by same position in current window + + if(window_blocking()) { + + // calculate buffer addresses and swap contents + + swap_contents(calc_rshadow(__found),calc_window(__curr),2); + break; + } + + // see if test window has a shadow + + if(__curr->wsbuf!=NULL) { + + // see if current position of window to activate is + // blocked by the right shadow of the test window + + if(rshadow_blocking()) { + swap_contents(calc_rshadow(__found),calc_rshadow(__curr),3); + break; + } + + // see if current position of window to activate is + // blocked by the bottom shadow of the test window + + if(bshadow_blocking()) { + swap_contents(calc_rshadow(__found),calc_bshadow(__curr),3); + break; + } + } + } + } + } + + // search bottom shadow + + startcol=__found->scol+2; + stopcol=__found->ecol+2; + __crow=__found->erow+1; + for(__ccol=startcol;__ccol<=stopcol;__ccol++) { + + // check all window records "above" shadow to activate + + for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) { + + // see if current position in shadow to activate + // is blocked by same position in test window + + if(window_blocking()) { + + // calculate buffer addresses and swap contents + + swap_contents(calc_bshadow(__found),calc_window(__curr),2); + break; + } + + // see if test window has a shadow + + if(__curr->wsbuf!=NULL) { + if(rshadow_blocking()) { + swap_contents(calc_bshadow(__found),calc_rshadow(__curr),3); + break; + } + if(bshadow_blocking()) { + swap_contents(calc_bshadow(__found),calc_bshadow(__curr),3); + break; + } + } + } + } + } + + // re-link pointer to window record to be activated + + prev=__found->prev; + next=__found->next; + if(prev!=NULL) + prev->next=next; + next->prev=prev; + gwin.active->next=__found; + __found->prev=gwin.active; + __found->next=NULL; + gwin.active=__found; + + // update help category + + if(gwin.active->help) + gwin.help=gwin.active->help; + + // reset cursor position + + vposset(gwin.active->row,gwin.active->column); + + // return normally + + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Activates a window without overlap checking + +int wactiv_(int whandle) { + + // if window is already active, ignore request + if(gwin.active and (whandle == gwin.active->whandle)) + return gwin.werrno = W_NOERROR; + + // find address of window's record + __found = wfindrec(whandle); + if(__found == NULL) + return gwin.werrno = W_NOTFOUND; + + // re-link pointer to window record to be activated + _wrec_t* prev = __found->prev; + _wrec_t* next = __found->next; + if(prev) + prev->next = next; + next->prev = prev; + gwin.active->next = __found; + __found->prev = gwin.active; + __found->next = NULL; + gwin.active = __found; + + // update help category + if(gwin.active->help) + gwin.help = gwin.active->help; + + // reset cursor position + vposset(gwin.active->row,gwin.active->column); + + // return normally + return gwin.werrno = W_NOERROR; +} + + +// ------------------------------------------------------------------ +// this function will update buffers above window string will be displayed in + +static void update_buffers(vatch* pcurr, int shadow) { + + _wrec_t *tcurr; + vattr tgattr; + + // put current string character and attribute into found window's buffer + + *pcurr = vcatch(*__p, __gattr); + + // if window's shadow is what's blocking, check to see + // if it is the highest shadow. If it is, display the + // character in the shadow's attribute, otherwise search + // for other blocking windows + + if(shadow) { + if(__curr->next==NULL) { + vputc(__crow, __ccol, __gattr & BLINK ? (__curr->wsattr | BLINK) : __curr->wsattr, *__p); + } + else { + tcurr = __curr; + __curr = __curr->next; + tgattr = __gattr; + __gattr = __curr->wsattr; + if(window_blocking()) + update_buffers(calc_window(__curr), 0); + else { + if(bshadow_blocking()) + update_buffers(calc_bshadow(__curr), 1); + else { + if(rshadow_blocking()) + update_buffers(calc_rshadow(__curr), 1); + } + } + __gattr = tgattr; + __curr = tcurr; + } + } +} + +// ------------------------------------------------------------------ + +int wwprintc(int whandle, int wrow, int wcol, vattr attr, const vchar chr) { + + // check for existance of active window or hidden windows + if(!gwin.total and gwin.hidden==NULL) + return gwin.werrno=W_NOACTIVE; + + // find address of window's record + _wrec_t* found = wfindrec(whandle); + if(found==NULL) { + found = gwin.hidden; + while(found) { + if(whandle==found->whandle) + break; + found = found->prev; + } + if(found==NULL) + return gwin.werrno=W_NOTFOUND; + } + + // display character + vputc(found->srow+wrow+found->border, found->scol+wcol+found->border, attr, chr); + + // return to caller + return gwin.werrno = W_NOERROR; +} + +// ------------------------------------------------------------------ + +int wwprints(int whandle, int wrow, int wcol, vattr attr, const char* str) { + + // check for existance of active window or hidden windows + if(!gwin.total and gwin.hidden==NULL) + return gwin.werrno=W_NOACTIVE; + + // find address of window's record + int hidden = NO; + _wrec_t* found = wfindrec(whandle); + if(found==NULL) { + found = gwin.hidden; + while(found) { + if(whandle==found->whandle) + break; + found = found->prev; + } + if(found==NULL) + return gwin.werrno=W_NOTFOUND; + hidden = YES; + } + + // see if window has a border + int border = found->border; + + // calculate effective coordinates + int ecol = found->ecol-border; + __crow = found->srow+wrow+border; + __ccol = found->scol+wcol+border; + __gattr = attr; + __p = str; + + // check for valid coordinates + if((__crow > (found->erow-border)) or (__ccol > ecol)) + return gwin.werrno=W_INVCOORD; + + // save current cursor position + int oldrow, oldcol; + if(gvid->isbios()) + vposget(&oldrow,&oldcol); + + // do while not end-of-string and not end-of-window + while(__ccol <= ecol and *__p) { + + // see if output window is hidden. if so, then there + // is no need to check for blocking windows/shadows + if(hidden) + *(calc_window(found)) = vcatch(*__p, attr); + else { + + // check all window records "above" window to activate + for(__curr=found->next; __curr!=NULL; __curr=__curr->next) { + + // see if current position in window to activate + // is blocked by same position in test window + if(window_blocking()) { + + // calculate buffer addresses and swap contents + update_buffers(calc_window(__curr), 0); + break; + } + + // see if test window has a shadow + if(__curr->wsbuf!=NULL) { + + // see if shadow to the right of test window is + // blocking the current position of window to activate + if(rshadow_blocking()) { + update_buffers(calc_rshadow(__curr), 1); + break; + } + + // see if shadow to the bottom of test window is + // blocking the current position of window to activate + if(bshadow_blocking()) { + update_buffers(calc_bshadow(__curr), 1); + break; + } + } + } + + // if current position is not blocked, + // then display char to screen + if(__curr==NULL) + vputc(__crow, __ccol, attr, *__p); + } + + // update pointer into string and current column + __ccol++; + __p++; + } + + // restore old cursor position + if(gvid->isbios()) + vposset(oldrow,oldcol); + + // return to caller + return gwin.werrno = *__p ? W_STRLONG : W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int wwprintstr(int whandle, int wrow, int wcol, vattr attr, const char* str) { + + // check for existance of active window or hidden windows + if(!gwin.total and gwin.hidden==NULL) + return gwin.werrno=W_NOACTIVE; + + // find address of window's record + _wrec_t* found = wfindrec(whandle); + if(found==NULL) { + found = gwin.hidden; + while(found) { + if(whandle==found->whandle) + break; + found = found->prev; + } + if(found==NULL) + return gwin.werrno=W_NOTFOUND; + } + + // display string + vputs(found->srow+wrow+found->border, found->scol+wcol+found->border, attr, str); + + // return to caller + return gwin.werrno = W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Changes the active window's border box type + +int wborder(int btype) { + + register int border; + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid box type + if((btype<0) or (btype>7)) + return gwin.werrno=W_INVBTYPE; + + // see if window is to have a border + border = (btype==5) ? NO : YES; + + // redraw window's border + vbox( + gwin.active->srow, + gwin.active->scol, + gwin.active->erow, + gwin.active->ecol, + btype, + border ? gwin.active->battr : gwin.active->wattr, + border ? gwin.active->loattr : gwin.active->wattr + ); + + // update window's record + gwin.active->btype=btype; + gwin.active->border=border; + + // see if cursor position needs to be updated + if((gwin.active->row==gwin.active->srow) or + (gwin.active->row==gwin.active->erow) or + (gwin.active->column==gwin.active->scol) or + (gwin.active->column==gwin.active->ecol)) { + wgotoxy(0,0); + } + + // re-display title if one exists + if(gwin.active->title!=NULL) + wtitle(gwin.active->title,gwin.active->tpos,gwin.active->tattr); + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Fills a region of active window w/specified char/attribute + +int wfill(int wsrow, int wscol, int werow, int wecol, vchar chr, vattr atr) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid coordinates + if(wchkbox(wsrow,wscol,werow,wecol)) + return gwin.werrno=W_INVCOORD; + + // check for window border + const int &border = gwin.active->border; + + // fill in specified region + vfill( + gwin.active->srow+wsrow+border, + gwin.active->scol+wscol+border, + gwin.active->srow+werow+border, + gwin.active->scol+wecol+border, + chr, + atr + ); + + // return with no error + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Returns the handle of the active window + +int whandle() { + + // test for active window + if(!gwin.total) { + gwin.werrno=W_NOACTIVE; + return 0; + } + + // return normally + gwin.werrno = W_NOERROR; + return gwin.active->whandle; +} + + +// ------------------------------------------------------------------ +// Displays text on window's top or bottom border + +int wmessage(const char* str, int border, int leftofs, vattr attr) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // make sure window has a border + if(!gwin.active->border) + return gwin.werrno=W_NOBORDER; + + int left = gwin.active->scol+1; + int right = gwin.active->ecol-1; + int width = right-left+1; + int len = strlen(str); + + // Center string + if(leftofs < 0) + leftofs = (len > (width-2)) ? left : (((width/2)+left)-(len/2)); + + // make sure string fits in window + if((gwin.active->scol+leftofs+len-1) > (gwin.active->ecol)) + return gwin.werrno=W_STRLONG; + + // display string + vputs(border ? gwin.active->erow : gwin.active->srow, gwin.active->scol+leftofs, attr, str); + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Proportion bar + +void wpropbar(int xx, int yy, long len, vattr attr, long pos, long size) { + + // xx, yy = start position in window. + // len = length (in chars) of progress field. + // attr = color to use for progress field. + // pos = present position. + // size = total size of field. + + const vchar barchar = _box_table(gwin.active->btype, 13); +#ifdef __UNIX__ // prefferable under xterm + const vchar thumbchar = ' '; + vattr thumbattr = revsattr(attr); +#else + const vchar thumbchar = '\xDB'; + vattr thumbattr = attr; +#endif + + long thumblen = (pos*len)/size; + + int x = xx; + if(thumblen != 0) { + wputx(yy, x, thumbattr|ACSET, thumbchar, thumblen); + x += thumblen; + } + if(thumblen != len) + wputx(yy, x, attr|ACSET, barchar, len-thumblen); +} + + +// ------------------------------------------------------------------ +// Gives active window a title + +int wtitle(const char* str, int tpos, vattr tattr) { + + // check for active window + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // redraw box if deleting or moving title + if(str==NULL or gwin.active->title!=NULL) { + if(gwin.active->border) { + vputx( + ((tpos&TBOTTOM) ? gwin.active->erow : gwin.active->srow), + gwin.active->scol+1, + gwin.active->battr|ACSET, + _box_table(gwin.active->btype, (tpos&TBOTTOM)?6:1), + gwin.active->ecol-gwin.active->scol-1 + ); + } + } + + // if not deleting the title, calculate position and display it + if(str) { + + int left = gwin.active->scol+1; + int right = gwin.active->ecol-1; + int width = right-left+1; + int len = strlen(str); + + // don't display title if window is borderless + if(gwin.active->border) { + + int start; + + switch(tpos&~TBOTTOM) { + case TLEFT: + //start = (len>(width-3)) ? left : (left+1); + start = left; + break; + case TCENTER: + start = (len>(width-2)) ? left : (((width/2)+left)-(len/2)); + break; + default: // default is TRIGHT + { + int offs = width-len; + if(offs>2) + offs--; + start = (len>width) ? left : (left+offs+1); + } + } + + // allocate space for window title string, and copy it there + char* p = (char*)throw_xmalloc(((width>len) ? width : len)+1); + if(p==NULL) + return gwin.werrno=W_ALLOCERR; + strcpy(p, str); + *(p+width) = NUL; + + // display title string + vputs((tpos&TBOTTOM)?gwin.active->erow:gwin.active->srow, start, tattr, p); + + // free allocated space + throw_xfree(p); + + } + } + + // update window's record + gwin.active->title=str; + gwin.active->tpos=tpos; + gwin.active->tattr=tattr; + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +void wscrollbar(int orientation, uint total, uint maxpos, uint pos, int sadd) { + + vattr attr = (gwin.active->sbattr == DEFATTR) ? gwin.active->battr : gwin.active->sbattr; + vattr invattr = revsattr(attr); + + const vchar barchar = _box_table(gwin.active->btype, 13); + const vchar arrowupchar = '\x18'; + const vchar arrowdownchar = '\x19'; + const vchar arrowleftchar = '\x1B'; + const vchar arrowrightchar = '\x1A'; +#ifdef __UNIX__ // prefferable under xterm + const vchar thumbchar = ' '; + vattr thumbattr = revsattr(attr); +#else + const vchar thumbchar = '\xDB'; + vattr thumbattr = attr; +#endif + + if(maxpos == 0) + maxpos = 1; + + uint visiblelen; + if(orientation == W_VERT) + visiblelen = (gwin.active->erow - (gwin.active->srow+sadd)) + 1 - (gwin.active->border?2:0); + else + visiblelen = (gwin.active->ecol - (gwin.active->scol+sadd)) + 1 - (gwin.active->border?2:0) - 2; + uint barlen = visiblelen - 2; + uint thumblen = (visiblelen*barlen) / total; + if(thumblen == 0) + thumblen = 1; + else if(thumblen > barlen) + thumblen = barlen; + uint maxthumbpos = barlen - thumblen; + uint thumbpos = (pos*maxthumbpos) / maxpos; + uint thumbdiv = (pos*maxthumbpos) % maxpos; + if((thumbdiv >= (maxpos/2)) and (maxpos > 1)) + thumbpos++; + if(thumbpos > maxthumbpos) + thumbpos = maxthumbpos; + barlen -= thumbpos + thumblen; + + if(orientation == W_VERT) { + uint scol = gwin.active->ecol - gwin.active->scol - gwin.active->border; + vputc((sadd++)+gwin.active->srow+gwin.active->border, gwin.active->ecol, invattr|ACSET, arrowupchar); + if(thumbpos != 0) { + wputy(sadd, scol, attr|ACSET, barchar, thumbpos); + sadd += thumbpos; + } + if(thumblen != 0) { + wputy(sadd, scol, thumbattr|ACSET, thumbchar, thumblen); + sadd += thumblen; + } + if(barlen != 0) { + wputy(sadd, scol, attr|ACSET, barchar, barlen); + sadd += barlen; + } + vputc(sadd+gwin.active->srow+gwin.active->border, gwin.active->ecol, invattr|ACSET, arrowdownchar); + } + else { + uint srow = gwin.active->erow - gwin.active->srow - gwin.active->border; + vputc(gwin.active->erow, (sadd++)+gwin.active->scol+gwin.active->border, invattr|ACSET, arrowleftchar); + if(thumbpos != 0) { + wputx(srow, sadd, attr|ACSET, barchar, thumbpos); + sadd += thumbpos; + } + if(thumblen != 0) { + wputx(srow, sadd, thumbattr|ACSET, thumbchar, thumblen); + sadd += thumblen; + } + if(barlen != 0) { + wputx(srow, sadd, attr|ACSET, barchar, barlen); + sadd += barlen; + } + vputc(gwin.active->erow, sadd+gwin.active->scol+gwin.active->border, invattr|ACSET, arrowrightchar); + } +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwindow.cpp b/goldlib/gcui/gwindow.cpp new file mode 100644 index 0000000..462f0cc --- /dev/null +++ b/goldlib/gcui/gwindow.cpp @@ -0,0 +1,92 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Windowing wrapper class. +// ------------------------------------------------------------------ + +#include +#include +#include + + +// ------------------------------------------------------------------ + +int gwindow::printf(const char* format, ...) { + + char buf[255]; + va_list argptr; + va_start(argptr,format); + int result = vsprintf(buf,format,argptr); + va_end(argptr); + puts(buf); + return result; +} + + +// ------------------------------------------------------------------ + +int gwindow::printf(vattr color, const char* format, ...) { + + char buf[255]; + va_list argptr; + va_start(argptr,format); + int result = vsprintf(buf,format,argptr); + va_end(argptr); + text_color(color); + puts(buf); + return result; +} + + +// ------------------------------------------------------------------ + +int gwindow::printf(int row, int col, const char* format, ...) { + + va_list argptr; + char buf[256]; + *buf = NUL; + va_start(argptr, format); + int result = vsprintf(buf, format, argptr); + va_end(argptr); + prints(row, col, window_color, buf); + return result; +} + + +// ------------------------------------------------------------------ + +int gwindow::printf(int row, int col, vattr color, const char* format, ...) { + + va_list argptr; + char buf[256]; + *buf = NUL; + va_start(argptr, format); + int result = vsprintf(buf, format, argptr); + va_end(argptr); + prints(row, col, color, buf); + return result; +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwindow.h b/goldlib/gcui/gwindow.h new file mode 100644 index 0000000..d6c4219 --- /dev/null +++ b/goldlib/gcui/gwindow.h @@ -0,0 +1,687 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Windowing class. +// ------------------------------------------------------------------ + +#ifndef __gwindow_h +#define __gwindow_h + + +// ------------------------------------------------------------------ + +#include +#include + +#undef getc +#undef putc + + +// ------------------------------------------------------------------ + +inline void wgetc(int wrow, int wcol, vattr* atr, vchar* chr) { + + vgetc(wrow+gwin.active->srow+gwin.active->border, wcol+gwin.active->scol+gwin.active->border, atr, chr); +} + + +// ------------------------------------------------------------------ + +struct gscrollbar_data { + long minpos; // Minimum range position + long maxpos; // Maximum range position + long pos; // Position of the thumb button + long page; // Size of the visible part +}; + + +// ------------------------------------------------------------------ + +class gwindow { + +protected: + + _wrec_t* wrec; + + int owner; + + int window_style; + + vattr window_color; + + vattr border_hi_color; + vattr border_lo_color; + + vattr scrollbar_color; + + vattr title_color; + int title_position; + + vattr message_color; + + vattr shadow_color; + +public: + + int start_row; + int start_column; + + int end_row; + int end_column; + + enum { + title_top = TTOP, + title_left = TLEFT, + title_center = TCENTER, + title_right = TRIGHT, + title_bottom = TBOTTOM, + border_top = TP_BORD, + border_bottom = BT_BORD, + border_left = LT_BORD, + border_right = RT_BORD, + scrollbar_horizontal = W_HORZ, + scrollbar_vertical = W_VERT, + direction_down = D_DOWN, + direction_up = D_UP, + direction_left = D_LEFT, + direction_right = D_RIGHT, + bordertype_single = BT_SINGLE, + bordertype_double = BT_DOUBLE, + bordertype_singletop = BT_SINGLETOP, + bordertype_doubletop = BT_DOUBLETOP, + bordertype_blanks = BT_BLANKS, + bordertype_none = BT_NONE, + bordertype_blocks = BT_BLOCKS, + bordertype_ascii = BT_ASCII, + bordertypes = 7 + }; + + gwindow(); + gwindow(int old_handle); + virtual ~gwindow(); + + void init(); + + int height() { return 1 + end_row - start_row; } + int width() { return 1 + end_column - start_column; } + + int border_type() { return window_style & bordertypes; } + bool has_border() { return border_type() != BT_NONE; } + + vchar boxchar_upper_left_corner() { return _box_table(border_type(), 0); } + vchar boxchar_upper_horizontal_line() { return _box_table(border_type(), 1); } + vchar boxchar_upper_right_corner() { return _box_table(border_type(), 2); } + vchar boxchar_left_vertical_line() { return _box_table(border_type(), 3); } + vchar boxchar_right_vertical_line() { return _box_table(border_type(), 4); } + vchar boxchar_lower_left_corner() { return _box_table(border_type(), 5); } + vchar boxchar_lower_horizontal_line() { return _box_table(border_type(), 6); } + vchar boxchar_lower_right_corner() { return _box_table(border_type(), 7); } + vchar boxchar_middle_junction() { return _box_table(border_type(), 8); } + vchar boxchar_left_vertical_junction() { return _box_table(border_type(), 9); } + vchar boxchar_right_vertical_junction() { return _box_table(border_type(), 10); } + vchar boxchar_upper_horizontal_junction() { return _box_table(border_type(), 11); } + vchar boxchar_lower_horizontal_junction() { return _box_table(border_type(), 12); } + + void set_window_at(int srow, int scol); + void set_window_size(int vlen, int hlen); + + void open(int srow, int scol, int erow, int ecol, int style, vattr bcolor, vattr wcolor, vattr sbcolor = DEFATTR, vattr locolor = DEFATTR); + void openxy(int srow, int scol, int vlen, int hlen, int style, vattr bcolor, vattr wcolor, vattr sbcolor = DEFATTR, vattr locolor = DEFATTR); + void open(); + void close(); + void unlink(); + + void hide(); + void unhide(); + + int active(); + void activate(); + void activate_quick(); + + int cursor_row(); + int cursor_column(); + + void text_color(vattr color); + + void move_cursor(int row, int column); + + void title(const char* title, vattr color = DEFATTR, int position=-1); + void no_title(); + + void message(const char* text, int border, int leftofs, vattr color = DEFATTR); + + void shadow(vattr color = DEFATTR); + void no_shadow(); + + void set_vscrollbar_range(int minpos, int maxpos, int visible, int total, int redraw); + void set_hscrollbar_range(int minpos, int maxpos, int visible, int total, int redraw); + + void set_vscrollbar_pos(int pos, int redraw); + void set_hscrollbar_pos(int pos, int redraw); + + void set_scrollbar_color(vattr color); + + void vscrollbar(uint total, uint maxpos, uint pos, int sadd=0); + void hscrollbar(uint total, uint maxpos, uint pos, int sadd=0); + + void scroll_down(int count=1); + void scroll_up(int count=1); + + void scroll_box_down(int scol, int srow, int ecol, int erow, int count=1); + void scroll_box_up(int scol, int srow, int ecol, int erow, int count=1); + + void getc(int row, int col, vattr* atr, vchar* chr); + + void putc(vchar ch); + void puts(const char* text); + void printc(int row, int col, vattr color, vchar ch); + void prints(int row, int col, vattr color, const char* text); + void printvs(int row, int col, vattr color, const vchar* text); + void prints(int row, int col, vattr color, const std::string& text); + void printns(int row, int col, vattr color, const char* text, int len, vchar fill=' ', vattr fill_color = DEFATTR); + + int printf(const char* format, ...) __attribute__ ((format (printf, 2, 3))); + int printf(vattr color, const char* format, ...) __attribute__ ((format (printf, 3, 4))); + int printf(int row, int col, const char* format, ...) __attribute__ ((format (printf, 4, 5))); + int printf(int row, int col, vattr color, const char* format, ...) __attribute__ ((format (printf, 5, 6))); + + void fill_char(vchar ch); + void fill(int wsrow, int wscol, int werow, int wecol, vchar ch, vattr color); + void vertical_line(int wsrow, int wscol, int count, int btype, vattr color); + void horizontal_line(int wsrow, int wscol, int count, int btype, vattr color); + void clear(vattr color = DEFATTR); + void clear_eol(); + void drag(int direction, int howmuch=1); + void slide(int row, int col); + void putx(int wrow, int wcol, vattr color, char chr, uint len); + void print_center(int row, vattr color, const char* text); +}; + + +// ------------------------------------------------------------------ + +inline void gwindow::init() { + + wrec = NULL; + start_row = start_column = 0; + end_row = gvid->curr.screen.rows - 1; + end_column = gvid->curr.screen.columns - 1; + window_style = 0; + window_color = BLACK_|_LGREY; + border_hi_color = BLUE_|_LGREY; + border_lo_color = DEFATTR; + scrollbar_color = DEFATTR; + title_color = BLUE_|_LGREY; + title_position = title_center; + message_color = BLUE_|_LGREY; + shadow_color = DGREY_|_BLACK; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::set_window_at(int srow, int scol) { + + start_row = srow; + start_column = scol; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::set_window_size(int vlen, int hlen) { + + end_row = start_row + vlen - 1; + end_column = start_column + hlen - 1; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::open(int srow, int scol, int erow, int ecol, int style, vattr bcolor, vattr wcolor, vattr sbcolor, vattr locolor) { + + start_row = srow; + start_column = scol; + end_row = erow; + end_column = ecol; + window_color = wcolor; + window_style = style; + border_hi_color = bcolor; + border_lo_color = locolor; + scrollbar_color = sbcolor; + + wopen(srow, scol, erow, ecol, style, bcolor, wcolor, sbcolor, locolor); + wrec = gwin.active; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::openxy(int srow, int scol, int vlen, int hlen, int style, vattr bcolor, vattr wcolor, vattr sbcolor, vattr locolor) { + + open(srow, scol, srow+vlen-1, scol+hlen-1, style, bcolor, wcolor, sbcolor, locolor); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::open() { + + open(start_row, start_column, end_row, end_column, window_style, border_hi_color, window_color, scrollbar_color, border_lo_color); +} + + +// ------------------------------------------------------------------ + +inline int gwindow::active() { + + return wrec == gwin.active; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::activate_quick() { + + if(!active()) + wactiv_(wrec->whandle); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::close() { + + if(wrec) { + activate_quick(); + wclose(); + wrec = NULL; + } +} + + +// ------------------------------------------------------------------ + +inline void gwindow::unlink() { + + wunlink(wrec->whandle); + wrec = NULL; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::hide() { + + activate_quick(); + whide(); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::unhide() { + + wunhide(wrec->whandle); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::activate() { + + if(!active()) + wactiv(wrec->whandle); +} + + +// ------------------------------------------------------------------ + +inline int gwindow::cursor_row() { + + return wrec->row; +} + + +// ------------------------------------------------------------------ + +inline int gwindow::cursor_column() { + + return wrec->column; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::text_color(vattr color) { + + window_color = color; + activate_quick(); + wtextattr(color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::set_scrollbar_color(vattr color) { + + wrec->sbattr = color; + scrollbar_color = color; +} + + +// ------------------------------------------------------------------ + +inline void gwindow::move_cursor(int row, int column) { + + activate_quick(); + wgotoxy(row, column); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::title(const char* title, vattr color, int position) { + + if(color != DEFATTR) + title_color = color; + if(position != -1) + title_position = position; + activate_quick(); + wtitle(title, title_position, title_color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::no_title() { + + title(NULL); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::message(const char* text, int border, int leftofs, vattr color) { + + if(color != DEFATTR) + message_color = color; + activate_quick(); + wmessage(text, border, leftofs, message_color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::shadow(vattr color) { + + if(color != DEFATTR) + shadow_color = color; + activate_quick(); + wshadow(shadow_color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::no_shadow() { + + activate_quick(); + wshadoff(); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::vscrollbar(uint total, uint maxpos, uint pos, int sadd) { + + activate_quick(); + wscrollbar(scrollbar_vertical, total, maxpos, pos, sadd); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::hscrollbar(uint total, uint maxpos, uint pos, int sadd) { + + activate_quick(); + wscrollbar(scrollbar_horizontal, total, maxpos, pos, sadd); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::scroll_down(int count) { + + activate_quick(); + wscroll(count, direction_down); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::scroll_up(int count) { + + activate_quick(); + wscroll(count, direction_up); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::scroll_box_down(int scol, int srow, int ecol, int erow, int count) { + + activate_quick(); + wscrollbox(scol, srow, ecol, erow, count, direction_down); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::scroll_box_up(int scol, int srow, int ecol, int erow, int count) { + + activate_quick(); + wscrollbox(scol, srow, ecol, erow, count, direction_up); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::getc(int row, int col, vattr* atr, vchar* chr) { + + activate_quick(); + wgetc(row, col, atr, chr); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::putc(vchar ch) { + + activate_quick(); + wputc(ch); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::puts(const char* text) { + + activate_quick(); + wputs(text); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::printc(int row, int col, vattr color, vchar ch) { + + activate_quick(); + wprintc(row, col, color, ch); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::prints(int row, int col, vattr color, const char* text) { + + activate_quick(); + wprints(row, col, color == DEFATTR ? window_color : color, text); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::printvs(int row, int col, vattr color, const vchar* text) { + + activate_quick(); + wprintvs(row, col, color == DEFATTR ? window_color : color, text); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::prints(int row, int col, vattr color, const std::string& text) { + + prints(row, col, color, text.c_str()); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::printns(int row, int col, vattr color, const char* text, int len, vchar fill, vattr fill_color) { + + activate_quick(); + wprintns(row, col, color, text, len, fill, fill_color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::fill_char(vchar ch) { + + activate_quick(); + wfillch(ch); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::fill(int wsrow, int wscol, int werow, int wecol, vchar ch, vattr color) { + + activate_quick(); + wfill(wsrow, wscol, werow, wecol, ch, color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::vertical_line(int wsrow, int wscol, int count, int btype, vattr color) { + + activate_quick(); + wvline(wsrow, wscol, count, btype, color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::horizontal_line(int wsrow, int wscol, int count, int btype, vattr color) { + + activate_quick(); + whline(wsrow, wscol, count, btype, color); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::clear(vattr color) { + + activate_quick(); + wcclear(color == DEFATTR ? window_color : color); +} + + +// ------------------------------------------------------------------ + +inline gwindow::gwindow() { + + init(); + owner = true; +} + + +// ------------------------------------------------------------------ + +inline gwindow::gwindow(int old_handle) { + + init(); + owner = false; + + wrec = wfindrec(old_handle); + + start_row = wrec->srow; + start_column = wrec->scol; + end_row = wrec->erow; + end_column = wrec->ecol; + window_color = wrec->wattr; + window_style = wrec->btype; + border_hi_color = wrec->battr; + border_lo_color = wrec->loattr; + scrollbar_color = wrec->sbattr; +} + + +// ------------------------------------------------------------------ + +inline gwindow::~gwindow() { + + if(owner) + close(); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::slide(int row, int col) { + + activate_quick(); + wslide(row, col); +} + + +// ------------------------------------------------------------------ + +inline void gwindow::print_center(int row, vattr color, const char* text) { + + activate_quick(); + wcenters(row, color, text); +} + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinhelp.h b/goldlib/gcui/gwinhelp.h new file mode 100644 index 0000000..d03fca3 --- /dev/null +++ b/goldlib/gcui/gwinhelp.h @@ -0,0 +1,124 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Help. +// ------------------------------------------------------------------ + +#ifndef __gwinhelp_h +#define __gwinhelp_h + + +// ------------------------------------------------------------------ + +#include +#include + + +// ------------------------------------------------------------------ +// Window help information record + +class _help_t { + +public: + + int help[20]; // help stack + const char* file; // help file name + int helpptr; // help stack pointer + gkey key; // help hot key + vattr winattr; // help window attribute + vattr textattr; // help window text attribute + vattr selattr; // selection text attribute + vattr barattr; // selection bar attribute + int srow; // help window start row + int scol; // help window start column + int erow; // help window end row + int ecol; // help window end column + int btype; // help window box type + int title; // display "Help" title? + VfvCP open; // pointer to open function + gfile* fp; // help file + long offset; // help file offset + + _help_t() + { + memset(help, 0, sizeof(help)); + file = NULL; + helpptr = -1; + key = 0; + winattr = BLACK_|_BLACK; + textattr = BLACK_|_BLACK; + selattr = BLACK_|_BLACK; + barattr = BLACK_|_BLACK; + srow = 3; + scol = 8; + erow = 21; + ecol = 71; + btype = 0; + title = YES; + open = NULL; + fp = NULL; + offset = 0; + } +}; + + +// ------------------------------------------------------------------ +// Help index file record definition + +#if defined(GOLD_CANPACK) +#pragma pack(1) +#endif + +typedef struct _hlpidx_t { + word help; + char category[30]; + long offset; +} Hlpr; + +#if defined(GOLD_CANPACK) +#pragma pack() +#endif + + +// ------------------------------------------------------------------ + +int whelpcat(int cat); +int whelpclr(); +int whelpdef(const char* file, gkey key, vattr winattr, vattr textattr, vattr selattr, vattr barattr, VfvCP open); +int whelpop(); +int whelpopc(); +int whelppcat(int cat); +int whelpush(); +int whelpushc(int cat); +int whelpwin(int srow, int scol, int erow, int ecol, int btype, int title); +void whelpcompile(const char* helpfile, long& offset); +inline int whelpundef() { return whelpdef(NULL,0,BLACK_|_BLACK,BLACK_|_BLACK,BLACK_|_BLACK,BLACK_|_BLACK,NULL); } + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinhlp1.cpp b/goldlib/gcui/gwinhlp1.cpp new file mode 100644 index 0000000..9072405 --- /dev/null +++ b/goldlib/gcui/gwinhlp1.cpp @@ -0,0 +1,763 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Help functions. +// Based on CXL by Mike Smedley. +// ------------------------------------------------------------------ +// esc_esc() emulate two Esc key pressed +// esc_pgdn() emulate key sequence Esc & PgDn +// esc_pgup() emulate key sequence Esc & PgUp +// not_found() display alert window "Help category not found" +// find_cat_name() search index for help category entry by name +// find_cat_number() search index for help category entry by numbe. +// find_page() search a page in the help file +// disp_cat() display a help category +// help_handler() display a window with help +// +// whelpdef() defines the help key, file, and window colors +// whelpwin() defines the help window boundaries +// whelpcat() sets the help category +// whelppcat() sets the help category, but pushes current one first +// whelpopc() pops the last saved help category into the void +// whelpclr() clears the help buffer +// whelpush() pushes the current help category onto the stack +// whelpushc() pushes the given help category onto the stack +// whelpop() pops last saved help category, sets current +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// ------------------------------------------------------------------ +// Constants + +#define MAXXREF 50 +#define BUFSIZE 80 +#define BASETAGID 200 + + +// ------------------------------------------------------------------ +// Global variables + +extern int gmnudropthrough; + + +// ------------------------------------------------------------------ +// Local variables + +static bool whelpclosefile = false; +static char* catarray[MAXXREF]; +static int arraycnt = 0; +static char buf[BUFSIZE+1]; + +_help_t whelp; + + +// ------------------------------------------------------------------ +// Help index file record definition + +static Hlpr recd; + + +// ------------------------------------------------------------------ + +static void esc_esc() { + + setonkey(Key_Esc,NULL,0); + kbput(Key_Esc); + kbput(Key_Esc); +} + + +// ------------------------------------------------------------------ + +static void esc_pgdn() { + + setonkey(Key_Esc,NULL,0); + setonkey(Key_PgDn,NULL,0); + kbput(Key_Esc); + kbput(Key_PgDn); +} + + +// ------------------------------------------------------------------ + +static void esc_pgup() { + + setonkey(Key_Esc,NULL,0); + setonkey(Key_PgUp,NULL,0); + kbput(Key_Esc); + kbput(Key_PgUp); +} + + +// ------------------------------------------------------------------ + +static void not_found(const char* cat) { + + wtextattr(whelp.textattr); + wputs("\nHelp category not found: "); + wputs(cat); + wputs("\nPress a key to continue."); + waitkey(); +} + + +// ------------------------------------------------------------------ + +static int find_cat_name(const char* cat) { + + int found=NO; + + // Reset file pointer. + whelp.fp->FseekSet(whelp.offset); + + // Check for "*I" marker. + whelp.fp->Fgets(buf, BUFSIZE); + if (strnieql(buf,"*I",2)) + { + // Search index for help category entry. If found, + // then advance file pointer to specified position. + for(;;) + { + whelp.fp->Fread(&recd,sizeof(Hlpr)); + if(recd.offset==-1L) + break; + if (strieql(recd.category,cat)) + { + whelp.fp->FseekSet(whelp.offset + recd.offset); + found=YES; + break; + } + } + } + + // If help category was not found, display an error message. + if(not found) + not_found(cat); + + return found; +} + + +// ------------------------------------------------------------------ + +static int find_cat_number(int cat) { + + int found=NO; + + // Reset file pointer. + whelp.fp->FseekSet(whelp.offset); + + // Check for "*I" marker. + whelp.fp->Fgets(buf, BUFSIZE); + if (strnieql(buf,"*I",2)) + { + // Search index for help category entry. If found, + // then advance file pointer to specified position. + for (;;) + { + whelp.fp->Fread(&recd,sizeof(Hlpr)); + if (recd.offset==-1L) + break; + if (recd.help==cat) + { + whelp.fp->FseekSet(whelp.offset + recd.offset); + found=YES; + break; + } + } + } + + // If help category was not found, display an error message. + if(!found) { + sprintf(buf, "%u", cat); + not_found(buf); + } + + return found; +} + + +// ------------------------------------------------------------------ + +static int find_page(long startpos, int pageofs) { + + long lastpagepos, currpos; + int currpage = 0; + int lines = whelp.srow; + + lastpagepos = currpos = startpos; + whelp.fp->FseekSet(startpos); + + while (currpage < pageofs) + { + whelp.fp->Fgets(buf, BUFSIZE); + if (not whelp.fp->okay()) + { + whelp.fp->FseekSet(lastpagepos); + break; + } + lines++; + currpos=whelp.fp->Ftell(); + if (strnieql(buf, "*E", 2)) + { + whelp.fp->FseekSet(lastpagepos); + break; + } + if(strnieql(buf, "*P", 2)) { + if(lines != whelp.srow+1) { + lastpagepos=currpos; + currpage++; + } + lines = whelp.srow; + } + else if(lines == whelp.erow-1) { + lastpagepos=currpos; + currpage++; + lines = whelp.srow; + } + } + + return currpage; +} + + +// ------------------------------------------------------------------ + +static void disp_cat() { + + int page, wrow, wcol, end, menuopen, itemopen; + long startpos; + _menu_t *curr; + char* p; + char* q; + gkey i, kbch; + + // initialize variables + page = wrow = wcol = end = menuopen = itemopen = 0; + + // save current info + startpos = whelp.fp->Ftell(); + curr = gwin.cmenu; + + // set text attribute + wtextattr(whelp.textattr); + + for(;;) { + + // read next line from help file into buffer + whelp.fp->Fgets(buf,BUFSIZE); + strtrim(buf); + + // if end-of-file or "*E" was found, assume end-of-category + end = strnieql(buf,"*E",2) ? YES : NO; + + bool pagebreak = false; + if(strnieql(buf,"*P",2)) { + if(wrow != whelp.srow) + pagebreak = true; + else + continue; + } + + // if end-of-category or new-page specified + if((wrow > whelp.erow-1) or pagebreak or end) + { + const char* _help = " Help "; + char _title[80]; + sprintf(_title, " %s ", recd.category); + wtitle(NULL, TTOP, whelp.winattr); + wtitle(_title, TLEFT, whelp.winattr); + wtitle(NULL, TCENTER|TBOTTOM, whelp.winattr); + wmessage(_help, TP_BORD, whelp.ecol-whelp.scol-strlen(_help), whelp.winattr); + + // update bottom border of window with PgUp/PgDn info + if(page and not end) p = " PgUp/PgDn "; + else if(not page and end) p = ""; + else if(page and end) p = " PgUp "; + else p = " PgDn "; + wmessage(p,BT_BORD,whelp.ecol-whelp.scol-strlen(p),whelp.winattr); + wmessage(" ESC ",BT_BORD,1,whelp.winattr); + + // if one or more cross reference menu items were specified + if (arraycnt) + { + // define the PgUp/PgDn/Esc keys + setonkey(Key_PgUp,esc_pgup,0); + setonkey(Key_PgDn,esc_pgdn,0); + setonkey(Key_Esc,esc_esc,0); + + // end the menu and process it + wmenuend(BASETAGID,M_OMNI|M_NOQS,0,0,whelp.selattr,whelp.selattr,BLACK_|_BLACK,whelp.barattr); + gmnudropthrough = YES; + kbch = i = (gkey)wmenuget(); + gmnudropthrough = NO; + + // free the keys that were defined + setonkey(Key_PgUp,NULL,0); + setonkey(Key_PgDn,NULL,0); + setonkey(Key_Esc,NULL,0); + + // turn off the menuopen flag and restore menu info + menuopen=NO; + gwin.cmenu=curr; + + // if Esc, PgDn, or PgUp was not pressed + if(i != 0xFFFF) { + + // convert tagid to array subscript + i -= (gkey)BASETAGID; + + // try to find selected category, if found set + // file pointer to it, otherwise reset file + // pointer back to previous help category + if (find_cat_name(catarray[i])) + startpos = whelp.fp->Ftell(); + else + whelp.fp->FseekSet(startpos); + + // clear help window and set + // position to upper left corner + wclear(); + wrow=page=0; + + // free menu item strings + for(i=0;iattr, q); + wcol += strlen(q); + q = p + 2; + } + else { + *p = NUL; + itemopen ^= 1; + wprints(wrow, wcol, gwin.active->attr, q); + if((not itemopen) and (arraycntattr, q); + wrow++; + wcol=0; + } +} /* disp_cat() */ + + +// ------------------------------------------------------------------ + +static void help_handler() { + + register int i; + int help,cat; + int found; + KBnd* savekb; + + // save help category + help=gwin.help; + + // temporarily un-define the onkey list to avoid collision + savekb=chgonkey(NULL); + + // hide cursor + int cursorwashidden = vcurhidden(); + vcurhide(); + + // hide mouse cursor + #ifdef GOLD_MOUSE + gmou.HideCursor(); + #endif + + // open help window + if(not wopen(whelp.srow, whelp.scol, whelp.erow, whelp.ecol, whelp.btype, whelp.winattr, whelp.winattr)) + return; + + // display window title if specified + if(whelp.title) + wtitle("[ Help ]",TCENTER,whelp.winattr); + + // see if an open function was given. If so, then call it + if(whelp.open) + (*whelp.open)(); + + // determine help category to use. If the current help category + // is empty, check the stack for a help category there + cat=help; + if(not cat) { + if(whelp.helpptr>-1) { + for(i=whelp.helpptr;i>=0;i--) { + if(whelp.help[i]) { + cat=whelp.help[i]; + break; + } + } + } + } + + // check for no defined help category + if(not cat) { + wtextattr(whelp.textattr); + wputs("\nNo help category defined.\nPress a key to continue."); + waitkey(); + } + else { + + if (not whelp.fp) + { + whelpclosefile = true; + whelp.fp = new gfile; throw_new(whelp.fp); + whelp.fp->Fopen(whelp.file,"rb"); + if (!whelp.fp->isopen()) + { + wtextattr(whelp.textattr); + wputs("\nHelp file not found: "); + wputs(whelp.file); + wputs("\nPress a key to continue."); + waitkey(); + } + } + + if (whelp.fp->isopen()) + { + whelp.fp->FseekSet(whelp.offset); + + // find help category in help file + found=find_cat_number(cat); + + // read and display help category text + if(found) + disp_cat(); + } + + if (whelpclosefile) + { + whelp.fp->Fclose(); + delete whelp.fp; + whelp.fp = NULL; + } + } + + // close help window + wclose(); + + // reset mouse info + #ifdef GOLD_MOUSE + if(gmou.FreeCursor()) + gmou.ShowCursor(); + #endif + + // reset cursor + if(not cursorwashidden) + vcurshow(); + + // clear any onkeys defined in "open" function and relink the onkey list + freonkey(); + chgonkey(savekb); + + // restore help category + gwin.help=help; +} + + +// ------------------------------------------------------------------ + +int whelpdef(const char* file, gkey key, vattr winattr, vattr textattr, vattr selattr, vattr barattr, VfvCP open) { + + // is help disengagement requested? If so, un-define the help key. + if(file==NULL) { + if(gwin.helptr==NULL) + return gwin.werrno=W_NOHLPDEF; + else { + gwin.helptr=NULL; + whelpclr(); + setonkey(whelp.key,NULL,0); + } + } + else { + + // attach help key to help handler + if(setonkey(key,help_handler,0)) + return gwin.werrno=W_ALLOCERR; + + // point global help info pointer to internal struct + gwin.helptr=&whelp; + } + + // add information to window help information record + whelp.file = file; + whelp.key = key; + whelp.winattr = winattr; + whelp.textattr = textattr; + whelp.selattr = selattr; + whelp.barattr = barattr; + whelp.open = open; + + // return with no error + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int whelpwin(int srow, int scol, int erow, int ecol, int btype, int title) { + + // make sure help has been defined + if(gwin.helptr==NULL) + return gwin.werrno=W_NOHLPDEF; + + // load given coordinates into local static structure + whelp.srow =srow; + whelp.scol =scol; + whelp.erow =erow; + whelp.ecol =ecol; + whelp.btype=btype; + whelp.title=title; + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int whelpcat(int cat) { + + // make sure help record has been defined + if(gwin.helptr==NULL) + return gwin.werrno=W_NOHLPDEF; + + // determine if help is to be global or window + if(gwin.active) + gwin.active->help=cat; + gwin.help=cat; + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int whelppcat(int cat) { + + // check for existance of help, and push + // current help category onto help stack + if(whelpush()) + return gwin.werrno; + + // set help category + return whelpcat(cat); +} + + +// ------------------------------------------------------------------ + +int whelpopc() { + + // make sure help has been defined + if(gwin.helptr==NULL) + return gwin.werrno=W_NOHLPDEF; + + // check for stack underflow + if(whelp.helpptr==-1) + return gwin.werrno=W_HLPSTKUN; + + // decrement stack pointer + whelp.helpptr--; + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int whelpclr() { + + // make sure help has been defined + if(gwin.helptr==NULL) + return gwin.werrno=W_NOHLPDEF; + + // clear help category and reset help stack pointer + gwin.help=0; + whelp.helpptr=-1; + + // return normally + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int whelpush() { + + // make sure help has been defined + if(gwin.helptr==NULL) + return(gwin.werrno=W_NOHLPDEF); + + // push the current help category onto the help stack + return(whelpushc(gwin.help)); +} + + +// ------------------------------------------------------------------ + +int whelpushc(int cat) { + + // make sure help has been defined + if(gwin.helptr==NULL) + return(gwin.werrno=W_NOHLPDEF); + + // check for stack overflow + if(gwin.helptr->helpptr==19) + return(gwin.werrno=W_HLPSTKOV); + + // add help category to stack and increment stack pointer + gwin.helptr->help[++gwin.helptr->helpptr]=cat; + + // return normally + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int whelpop() { + + // make sure help has been defined + if(gwin.helptr==NULL) + return(gwin.werrno=W_NOHLPDEF); + + // check for stack underflow + if(gwin.helptr->helpptr==-1) + return(gwin.werrno=W_HLPSTKUN); + + // restore help category and decrement stack pointer + gwin.help=gwin.helptr->help[gwin.helptr->helpptr--]; + if(gwin.active) + gwin.active->help=gwin.help; + + // return normally + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinhlp2.cpp b/goldlib/gcui/gwinhlp2.cpp new file mode 100644 index 0000000..73c8a06 --- /dev/null +++ b/goldlib/gcui/gwinhlp2.cpp @@ -0,0 +1,101 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Help file compiler. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include + +// ------------------------------------------------------------------ + +extern _help_t whelp; + +// ------------------------------------------------------------------ + +void whelpcompile(const char* helpfile, long& offset) { + + gfile ifp(helpfile, "rb"); + if (ifp.isopen()) + { + ifp.SetvBuf(); + + int count = 0; + char buf[1024]; + while (ifp.Fgets(buf, sizeof(buf))) + { + if(strnieql(buf, "*B ", 3)) + count++; + } + ifp.Rewind(); + + Hlpr* helpindex = (Hlpr*)throw_xcalloc(count+2, sizeof(Hlpr)); + + long relative_offset = 0; + + whelp.fp->Fputs("*I\r\n"); + whelp.fp->Fwrite(helpindex, count+1, sizeof(Hlpr)); + whelp.fp->Fputs("\r\n\r\n"); + relative_offset += 4 + ((count+1)*sizeof(Hlpr)) + 4; + + int counter = 0; + bool comment = true; + while (ifp.Fgets(buf, sizeof(buf))) + { + if(strnieql(buf, "*B ", 3)) { + comment = false; + helpindex[counter].help = atow(buf+3); + char* ptr = strchr(buf, ','); + strbtrim(strcpy(helpindex[counter].category, ptr ? ptr+1 : "")); + helpindex[counter].offset = relative_offset + strlen(buf); + counter++; + } + if (not comment) + { + whelp.fp->Fputs(buf); + relative_offset += strlen(buf); + } + if(strnieql(buf, "*E", 2)) + comment = true; + } + helpindex[counter].offset = -1L; + + whelp.fp->FseekSet(offset); + whelp.fp->Fputs("*I\r\n"); + whelp.fp->Fwrite(helpindex, count+1, sizeof(Hlpr)); + offset += relative_offset; + whelp.fp->FseekSet(offset); + + throw_xfree(helpindex); + + ifp.Fclose(); + } +} /* whelpcompile() */ + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwininit.cpp b/goldlib/gcui/gwininit.cpp new file mode 100644 index 0000000..30c55e1 --- /dev/null +++ b/goldlib/gcui/gwininit.cpp @@ -0,0 +1,328 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Windowing kernel. +// Based on CXL by Mike Smedley. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include + + +// ------------------------------------------------------------------ + +#define GOLD_INLINE inline +#define GOLD_WCHK + + +// ------------------------------------------------------------------ +// Global window data + +GWin gwin; + + +// ------------------------------------------------------------------ +// Window Class constructor + +GWin::GWin() { + + active = NULL; // pointer to active window + hidden = NULL; // pointer to last hidden window + menu = NULL; // pointer to head menu record + cmenu = NULL; // pointer to current menu record + helptr = NULL; // pointer to help info record + handle = 0; // last handle given to a window + help = 0; // pointer to current help category + werrno = W_NOERROR; // error num from last window func + total = 0; // total number of open windows + mlevel = 0; // system variable used in menus + ilevel = 0; // system variable used in menus + esc = true; // check for Esc in input funcions? + tabwidth = 8; // window TTY output tab width + fillch = ' '; // character to fill windows with + style = STYLE_NORMAL; // window opening style +} + + +// ------------------------------------------------------------------ +// Window Class destructor + +GWin::~GWin() { + + // No action defined yet +} + + +// ------------------------------------------------------------------ +// Displays a string in centered in active window + +int wcenters(int wrow, vattr attr, const char* str) { + + register int window_width, string_length; + int start_column, border; + + // check for active window + + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid row + + if(wchkcoord(wrow,0)) + return gwin.werrno=W_INVCOORD; + + // check for window border + + border=gwin.active->border; + + // calculate start column & window width + + start_column = gwin.active->scol+border; + window_width = (gwin.active->ecol-border)-start_column+1; + + // check length of input string + + string_length=strlen(str); + if(string_length>window_width) + return gwin.werrno=W_STRLONG; + + // display the string + + vputs( + gwin.active->srow+wrow+border, + ((window_width/2)+start_column)-(string_length/2), + attr, + str + ); + + // return normally + + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ +// Smoothly drag a window 1 position in given direction + +int wdrag(int direction) { + + int srow, scol, erow, ecol, fill_row, fill_col, i; + int nsrow, nscol, nerow, necol; + vattr shad_attr = DEFATTR; + int chars_per_line, lines_per_win; + int vert_movement, horz_movement; + vsavebuf* win_image; + vsavebuf* wp; + vatch* p; + register vatch* src; + register vatch* dest; + + // check for active window + if(!gwin.total) + return(gwin.werrno=W_NOACTIVE); + + // get window coordinates + srow = gwin.active->srow; + scol = gwin.active->scol; + erow = gwin.active->erow; + ecol = gwin.active->ecol; + + // calculate lines-per-window and characters-per-line + lines_per_win = erow - srow + 1; + chars_per_line = ecol - scol + 1; + + // determine facts about direction of move + vert_movement=horz_movement=0; + switch(direction) { + case D_DOWN: + vert_movement=1; + lines_per_win--; + break; + case D_UP: + vert_movement=-1; + lines_per_win--; + break; + case D_LEFT: + horz_movement=-1; + chars_per_line--; + break; + case D_RIGHT: + default: + horz_movement=1; + chars_per_line--; + } + + // calculate new window coordinates + nsrow = srow + vert_movement; + nscol = scol + horz_movement; + nerow = erow + vert_movement; + necol = ecol + horz_movement; + + // if window has shadow, close it before the move + if(gwin.active->wsbuf!=NULL) { + shad_attr = gwin.active->wsattr; + wshadoff(); + } + + // save the current window image + win_image = vsave(srow,scol,erow,ecol); + if(win_image==NULL) + return(gwin.werrno=W_ALLOCERR); + + // save the area where the window will relocate to + wp = vsave(nsrow,nscol,nerow,necol); + if(wp==NULL) { + throw_xfree(win_image); + return(gwin.werrno=W_ALLOCERR); + } + + // restore window to new coordinates + vrestore(win_image, nsrow, nscol, nerow, necol); + throw_xfree(win_image); + + // start buffer positions past coordinates + src = gwin.active->wbuf->data; + dest = wp->data; + + if(direction==D_DOWN) + src += chars_per_line; + if(direction==D_UP) + dest += chars_per_line; + + // do the transfer of buffer contents + for(i=0; i < lines_per_win; i++) { + + if(direction==D_LEFT) + dest++; + if(direction==D_RIGHT) + src++; + + // move 1 line + memmove(dest, src, chars_per_line*sizeof(vatch)); + src += chars_per_line; + dest += chars_per_line; + + if(direction==D_LEFT) + src++; + if(direction==D_RIGHT) + dest++; + } + + // erase the trail that was left-over + p = gwin.active->wbuf->data; + if(vert_movement) { + if(direction==D_DOWN) + fill_row=srow; + else { + p += (lines_per_win * chars_per_line); + fill_row=erow; + } + + vputx(fill_row, scol, vgattr(*p), vgchar(*p), ecol-scol+1); + } + else { + if(direction==D_RIGHT) + fill_col=scol; + else { + p += chars_per_line; + fill_col=ecol; + } + + for(i=srow;i<=erow;i++,p+=chars_per_line+1) + vputc(i, fill_col, vgattr(*p), vgchar(*p)); + } + + // free old window buffer + throw_xfree(gwin.active->wbuf); + + // update window record + gwin.active->wbuf = wp; + gwin.active->row = gwin.active->row - gwin.active->srow + nsrow; + gwin.active->column = gwin.active->column - gwin.active->scol + nscol; + gwin.active->srow = nsrow; + gwin.active->scol = nscol; + gwin.active->erow = nerow; + gwin.active->ecol = necol; + + // if window has shadow, redraw it + if(shad_attr != DEFATTR) + wshadow(shad_attr); + + // reset cursor position + vposset(gwin.active->row,gwin.active->column); + + // return normally + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ +// Slides active window to a new location + +int wslide(int nsrow, int nscol) { + + vattr shattr = DEFATTR; + int err = 0; + + // check for active windows + if(!gwin.total) + return gwin.werrno=W_NOACTIVE; + + // check for valid coordinates + if(nsrow<0 or nscol<0) + return gwin.werrno=W_INVCOORD; + + // if window has shadow, close it before the move + if(gwin.active->wsbuf!=NULL) { + shattr = gwin.active->wsattr; + wshadoff(); + } + + // slide it on over + while(gwin.active->scol>nscol and !err) err = wdrag(D_LEFT); + while(gwin.active->scolsrow>nsrow and !err) err = wdrag(D_UP); + while(gwin.active->srow + + +// ------------------------------------------------------------------ + +#define HORZ 0 +#define VERT 1 + + +// ------------------------------------------------------------------ + +#define ULC _box_table(bt, 0) // upper left corner +#define UHL _box_table(bt, 1) // upper horizontal line +#define URC _box_table(bt, 2) // upper right corner +#define LVL _box_table(bt, 3) // left vertical line +#define RVL _box_table(bt, 4) // right vertical line +#define LLC _box_table(bt, 5) // lower left corner +#define LHL _box_table(bt, 6) // lower horizontal line +#define LRC _box_table(bt, 7) // lower right corner +#define MJ _box_table(bt, 8) // middle junction +#define LVJ _box_table(bt, 9) // left vertical junction +#define RVJ _box_table(bt, 10) // right vertical junction +#define UHJ _box_table(bt, 11) // upper horizontal junction +#define LHJ _box_table(bt, 12) // lower horizontal junction + + +// ------------------------------------------------------------------ + +static int disp_char(int wrow,int wcol, vattr attr,int btype,vchar ch,int direc) { + + attr = attr|ACSET; + + // see if next to a border, if so, connect to it + if(gwin.active->border) { + + // abbreviate pointer + const int bt = btype; + + // calculate effective row and column + int row = gwin.active->srow+gwin.active->border+wrow; + int col = gwin.active->scol+gwin.active->border+wcol; + + // see if this is a horizontal or vertical line + if(direc==HORZ) { + + // make sure that the box type characters match + if(LVL==_box_table(gwin.active->btype, 3)) { + + // check left border + if(col==(gwin.active->scol+1)) { + vputc(row,gwin.active->scol,attr,LVJ); + ch=UHL; + } + + // check right border + if(col==(gwin.active->ecol-1)) { + vputc(row,gwin.active->ecol,attr,RVJ); + ch=UHL; + } + } + } + else { + + // make sure that the box type characters match + if(UHL==_box_table(gwin.active->btype, 1)) { + + // check top border + if(row==(gwin.active->srow+1)) { + vputc(gwin.active->srow,col,attr,UHJ); + ch=LVL; + } + + // check bottom border + if(row==(gwin.active->erow-1)) { + vputc(gwin.active->erow,col,attr,LHJ); + ch=LVL; + } + } + } + } + + // display character + if(wprintc(wrow,wcol,attr,ch)) + return gwin.werrno; + + // return normally + return 0; +} /* disp_char() */ + + +// ------------------------------------------------------------------ + +static inline int isupvert(int btype, vchar ch) { + + const int bt = btype; + return (ch==LVL or ch==UHJ or ch==ULC or ch==URC or ch==LVJ or ch==RVJ or ch==MJ) ? YES : NO; +} + + +// ------------------------------------------------------------------ + +static inline int isdownvert(int btype, vchar ch) { + + const int bt = btype; + return (ch==LVL or ch==LHJ or ch==LLC or ch==LRC or ch==LVJ or ch==RVJ or ch==MJ) ? YES : NO; +} + + +// ------------------------------------------------------------------ + +static inline int islefthorz(int btype, vchar ch) { + + const int bt = btype; + return (ch==UHL or ch==LVJ or ch==LLC or ch==ULC or ch==UHJ or ch==LHJ or ch==MJ) ? YES : NO; +} + + +// ------------------------------------------------------------------ + +static inline int isrighthorz(int btype, vchar ch) { + + const int bt = btype; + return (ch==UHL or ch==RVJ or ch==LRC or ch==URC or ch==UHJ or ch==LHJ or ch==MJ) ? YES : NO; +} + + +// ------------------------------------------------------------------ + +int whline(int wsrow, int wscol, int count, int btype, vattr attr) { + + register int bt; + int row,col,up,down; + vchar ch; + + row=wsrow; + col=wscol; + + // abbreviate pointer + bt = btype; + + if(count) { + + // see if a left junction or corner is needed + up = isupvert (btype,wgetc(row-1,col)); + down = isdownvert(btype,wgetc(row+1,col)); + if(up and down) + ch=LVJ; + else if(up) + ch=LLC; + else if(down) + ch=ULC; + else + ch=UHL; + + // display leftmost character + if(disp_char(row,col,attr,btype,ch,HORZ)) + return gwin.werrno; + col++; + count--; + } + + // do while not last character + while(count>1) { + + // see if a middle junction is needed + up = isupvert (btype,wgetc(row-1,col)); + down = isdownvert(btype,wgetc(row+1,col)); + if(up and down) + ch=MJ; + else if(up) + ch=LHJ; + else if(down) + ch=UHJ; + else + ch=UHL; + + // display middle character + if(disp_char(row,col,attr,btype,ch,HORZ)) + return gwin.werrno; + col++; + count--; + } + + if(count) { + + // see if a right junction or corner is needed + up = isupvert (btype,wgetc(row-1,col)); + down = isdownvert(btype,wgetc(row+1,col)); + if(up and down) + ch=RVJ; + else if(up) + ch=LRC; + else if(down) + ch=URC; + else + ch=UHL; + + // display rightmost character + if(disp_char(row,col,attr,btype,ch,HORZ)) + return gwin.werrno; + } + + // return normally + return gwin.werrno=W_NOERROR; +} /* whline() */ + + +// ------------------------------------------------------------------ + +int wvline(int wsrow, int wscol, int count, int btype, vattr attr) { + + register int bt; + int row,col,left,right; + vchar ch; + + row=wsrow; + col=wscol; + + // abbreviate pointer + bt = btype; + + if(count) { + + // see if a top junction or corner is needed + left = islefthorz (btype,wgetc(row,col-1)); + right = isrighthorz(btype,wgetc(row,col+1)); + if(left and right) + ch=UHJ; + else if(left) + ch=URC; + else if(right) + ch=ULC; + else + ch=LVL; + + // display uppermost character + if(disp_char(row,col,attr,btype,ch,VERT)) + return gwin.werrno; + row++; + count--; + } + + // do while not last character + while(count>1) { + left = islefthorz (btype,wgetc(row,col-1)); + right = isrighthorz(btype,wgetc(row,col+1)); + if(left and right) + ch=MJ; + else if(left) + ch=RVJ; + else if(right) + ch=LVJ; + else + ch=LVL; + + // display middle character + if(disp_char(row,col,attr,btype,ch,VERT)) + return gwin.werrno; + row++; + count--; + } + + if(count) { + + // see if a bottom junction or corner is needed + left = islefthorz (btype,wgetc(row,col-1)); + right = isrighthorz(btype,wgetc(row,col+1)); + if(left and right) + ch=LHJ; + else if(left) + ch=LRC; + else if(right) + ch=LLC; + else + ch=LVL; + + // display bottommost character + if(disp_char(row,col,attr,btype,ch,VERT)) + return gwin.werrno; + } + + // return normally + return gwin.werrno=W_NOERROR; +} /* wvline() */ + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinmenu.cpp b/goldlib/gcui/gwinmenu.cpp new file mode 100644 index 0000000..1d10288 --- /dev/null +++ b/goldlib/gcui/gwinmenu.cpp @@ -0,0 +1,1460 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Pseudo graphical menu. +// Based on CXL by Mike Smedley. +// ------------------------------------------------------------------ +// wmenubeg() starts a menu definition +// wmenuitem() defines a menu item +// wmenuend() ends a menu definition +// wmenuget() processes the defined menu +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__USE_ALLOCA__) + #include +#endif + + +// ------------------------------------------------------------------ + +int _overtagid; +int _finaltagid; + +int gmnudropthrough = NO; + + +// ------------------------------------------------------------------ +// prototypes for local functions + +static _item_t* down_item(_item_t *curr); +static _item_t* left_item(_item_t *curr); +static _item_t* right_item(_item_t *curr); +static _item_t* up_item(_item_t *curr); + + +// ------------------------------------------------------------------ +// menu item movement definitions + +#define ITM_LT 0 +#define ITM_RT 1 +#define ITM_UP 2 +#define ITM_DN 3 +#define ITM_FR 4 +#define ITM_LS 5 + + +// ------------------------------------------------------------------ +// array of function pointers to some of the item movement functions + +static _item_t *(*mnu_funcs[4])(_item_t *) = { + left_item, + right_item, + up_item, + down_item +}; + +// ------------------------------------------------------------------ +// flag used for initial display of menu selections + +static int dispdesc=YES; + + +// ------------------------------------------------------------------ +// this function will calculate the width of the selection bar + +static int calc_bar_width(_menu_t *wmenu,_item_t *witem) +{ + register int width; + + width=strlen(witem->str); + if(wmenu->barwidth) width=wmenu->barwidth; + return(width); +} + + +// ------------------------------------------------------------------ +// this function will calculate the window column +// at the center of the given menu item + +static int calc_center_item(_item_t *item) +{ + return( ((int)item->wcol) + (strlen(item->str)/2) ); +} + + +// ------------------------------------------------------------------ +// this function will hide the mouse cursor +// if mouse cursor mode is on + +static void hide_mouse_cursor_mnu(void) { + + #ifdef GOLD_MOUSE + if(gmou.FreeCursor()) + gmou.HideCursor(); + #endif +} + + +// ------------------------------------------------------------------ +// this function will display the mouse +// cursor if mouse cursor mode is on + +static void show_mouse_cursor_mnu(void) { + + #ifdef GOLD_MOUSE + if(gmou.FreeCursor()) { + gmou.ShowCursor(); + gmou.SetCursor(0,0xFFFF,((LGREY_|_LGREY)<<8)); + } + #endif +} + + +// ------------------------------------------------------------------ +// this function calls the given function + +static void mnu_call_func(VfvCP func) { + + _menu_t *menu; + int w; + int err; + + hide_mouse_cursor_mnu(); + menu=gwin.cmenu; + w=whandle(); + err=whelpush(); + (*func)(); + wactiv(w); + if(!err) whelpop(); + gwin.cmenu=menu; + show_mouse_cursor_mnu(); +} + + +// ------------------------------------------------------------------ +// this function will call a menu item's "after" function if it exists + +static void call_after(_item_t *citem) +{ + if(citem->after!=NULL) + mnu_call_func(citem->after); +} + + +// ------------------------------------------------------------------ +// this function will call a menu item's "before" function if it exists + +static void call_before(_item_t *citem) +{ + if(citem->before!=NULL) + mnu_call_func(citem->before); +} + + +// ------------------------------------------------------------------ +// this function closes the current menu's window and reactivates +// the menu window open prior to opening the current menu window + +static void close_window(int w) +{ + if(!gwin.cmenu->usecurr) { + hide_mouse_cursor_mnu(); + wclose(); + wactiv(w); + show_mouse_cursor_mnu(); + } +} + + +// ------------------------------------------------------------------ +// this function displays a menu selection, using selection bar if specified + +static void disp_item(_item_t *witem,int bar) +{ +#if defined(__USE_ALLOCA__) + char *buf = (char *)alloca(sizeof(vatch)*gvid->numcols); +#else + __extension__ char buf[sizeof(vatch)*gvid->numcols]; +#endif + char ch; + vattr chattr; + _wrec_t* whp; + register const char* p; + register vatch* ptr=(vatch*)buf; + int i, textend,width,wcol,found=NO; + + // if mouse cursor is on, temporarily hide it + hide_mouse_cursor_mnu(); + + // initialize width of output and end of text + p = witem->str; + width = calc_bar_width(gwin.cmenu,witem); + textend = gwin.cmenu->textpos+strlen(p)-1; + wgotoxy(witem->wrow,wcol=witem->wcol); + if (width > (gvid->numcols-2)) width = gvid->numcols - 2; + + // display separators + if (witem->fmask & M_SEPAR) + { + const int &border = gwin.active->border; + const int &btype = gwin.active->btype; + const vattr &attr = gwin.active->loattr; + vatch line = vcatch(_box_table(btype, 1), attr); + + if (border) *ptr++ = vcatch(_box_table(btype, 9), attr); + for (i = 0; i < width; i++) *ptr++ = line; + if (border) *ptr = vcatch(_box_table(btype, 10), attr); + + int row = gwin.active->srow + witem->wrow + border; + int col = gwin.active->scol + wcol; + vputws(row, col, (vatch*)buf, width+2); + } + else + { + // display menu item including selection bar + for(i=0; itextpos) or (i>textend)) ? ' ' : (*p++); + + // select attribute of character to be displayed based upon if + // selection bar was specified, if the menu item is non-selectable, + // if the character is a tag character, or none of the above. + if(bar) + chattr = gwin.cmenu->barattr; + else if(witem->fmask&M_NOSEL) + chattr = gwin.cmenu->noselattr; + else if((ch==witem->schar) and not found) { + found = YES; + chattr = gwin.cmenu->scharattr; + } + else + chattr = gwin.cmenu->textattr; + + // display character in selected attribute + //wprintc(witem->wrow,wcol++,chattr,ch); + + // Build menu line buffer + + *ptr++ = vcatch(ch,chattr); + } + + // Display complete buffer + wprintws(witem->wrow, wcol, (vatch*)buf, width); + } + + // display text description, if one exists + if((witem->desc!=NULL) and dispdesc) { + whp = wfindrec(witem->dwhdl); + i = (1 + whp->ecol - whp->scol) - (whp->border ? 2 : 0); + sprintf(buf, "%-*.*s", i, i, witem->desc); + wwprints(witem->dwhdl, witem->dwrow, witem->dwcol, witem->dattr, buf); + } + + // if mouse cursor is hidden, unhide it + show_mouse_cursor_mnu(); +} + + +// ------------------------------------------------------------------ +// this function finds the next menu selection down + +static _item_t * down_item(_item_t *curr) +{ + _item_t *best,*temp; + int brow,bcol,tcol,trow,crow,ccol,tdist,bdist; + + // initialize best record to NULL + best=NULL; + brow=bcol=32767; + + // calculate window column at center of current item + crow=(int)curr->wrow; + ccol=calc_center_item(curr); + + // search backwards through linked list, testing each item + for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) { + + // calculate window column at center of test item + trow=(int)temp->wrow; + tcol=calc_center_item(temp); + + if(trow>crow) { + tdist=abs((ccol-tcol)); + bdist=abs((ccol-bcol)); + if((trowwrow=-1; + best=down_item(temp); + throw_free(temp); + } + } + else + // see if menu selection is non-selectable + if(best->fmask&M_NOSEL) + best=down_item(best); + + // return best record + return(best); +} + + +// ------------------------------------------------------------------ +// this function finds the upper-leftmost menu selection + +static _item_t * first_item(void) +{ + _item_t *best,*temp; + + // initialize best record to highest record in linked list + best=gwin.cmenu->item; + + // search backwards through linked list, testing each item + for(temp=best->prev;temp!=NULL;temp=temp->prev) { + if((temp->wrowwrow) or ((temp->wrow==best->wrow) and (temp->wcolwcol))) + best=temp; + } + + // see if menu selection is non-selectable + if(best->fmask&M_NOSEL) best=right_item(best); + + // return best record + return(best); +} + + +// ------------------------------------------------------------------ +// this is a recursive function that frees a menu and all of its submenus + +static void free_menu(_menu_t *wmenu) +{ + _item_t *witem; + + // free all items in menu, including sub-menus + while(wmenu->item!=NULL) { + if(wmenu->item->child!=NULL) free_menu((_menu_t*)wmenu->item->child); + witem=wmenu->item->prev; + throw_free(wmenu->item); + wmenu->item=witem; + if(wmenu->item!=NULL) wmenu->item->next=NULL; + } + + // free the menu itself + throw_free(wmenu); +} + + +// ------------------------------------------------------------------ +// this function will find the bottom-rightmost menu selection + +static _item_t * last_item(void) +{ + _item_t *best,*temp; + int bcol; + + // initialize best record to highest record in linked list + best=gwin.cmenu->item; + bcol=best->wcol; + + // search backwards through linked list, testing each item + for(temp=best->prev;temp!=NULL;temp=temp->prev) { + if((temp->wrow>best->wrow) or ((temp->wrow==best->wrow) and (temp->wcol>bcol))) { + best=temp; + bcol=best->wcol; + } + } + + // see if menu selection is non-selectable + if(best->fmask&M_NOSEL) best=left_item(best); + + // return best record + return(best); +} + + +// ------------------------------------------------------------------ +// this function is called after a menu bar move + +static void post_move(_item_t *citem) +{ + gwin.cmenu->citem=citem; + gwin.help=citem->help; + disp_item(citem,1); + call_before(citem); +} + + +// ------------------------------------------------------------------ +// this function prepares for a menu bar move + +static void pre_move(_item_t *citem) +{ + disp_item(citem,0); + call_after(citem); +} + + +// ------------------------------------------------------------------ +// this function moves the selection bar to another menu item, +// automatically taking care of necessary pre/post move actions + +static _item_t * goto_item(_item_t *citem,int which) +{ + _item_t *item; + + if(which==ITM_FR) item=first_item(); + else if(which==ITM_LS) item=last_item(); + else item=(*mnu_funcs[which])(citem); + if(item!=citem) { + pre_move(citem); + post_move(citem=item); + } + return(citem); +} + + +// ------------------------------------------------------------------ +// this function will find the menu selection to the left of current + +static _item_t * left_item(_item_t *curr) +{ + _item_t *best,*temp; + int wwidth,bpos,tpos,cpos; + + // calculate window width and current position + wwidth=gwin.cmenu->ecol - gwin.cmenu->scol + 1; + cpos=(curr->wrow * wwidth) + curr->wcol; + + // initialize best record to NULL, and best position to -1 + best=NULL; + bpos=-1; + + // search backwards through linked list, testing each item + for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) { + + // calculate position of test each item + tpos=(temp->wrow*wwidth) + temp->wcol; + + // compare position of test item with best item, current item + if((tpos>bpos) and (tposfmask&M_NOSEL) + best=left_item(best); + + // return best record + return(best); +} + + +// ------------------------------------------------------------------ +// this function determines if the mouse cursor is on a menu item + +#ifdef GOLD_MOUSE +static _item_t *mouse_on_item(_menu_t *menu,int mcrow,int mccol) +{ + int srow,scol,border,start,end; + _item_t *item,*found; + + found = NULL; + srow = menu->srow; + scol = menu->scol; + border = menu->btype==5?0:1; + for(item=menu->item;item!=NULL;item=item->prev) { + if(mcrow==(srow+border+item->wrow)) { + start = scol+border+item->wcol; + end = start+calc_bar_width(menu,item)-1; + if((mccol>=start) and (mccol<=end)) { + found=item; + break; + } + } + } + return(found); +} +#endif + + +// ------------------------------------------------------------------ + +static void pre_exit(int w,int close) +{ + _menu_t *wmenu; + + hide_mouse_cursor_mnu(); + + // if not using current window for menu, then close it + if(close) close_window(w); + + // if at highest menu then free the whole menu structure + if(gwin.cmenu==gwin.menu) { + wmenu=gwin.menu->prev; + if(gwin.cmenu!=NULL) + free_menu(gwin.cmenu); + gwin.menu=wmenu; + if(gwin.menu!=NULL) + gwin.menu->next=NULL; + gwin.cmenu=gwin.menu; + } +} + + +// ------------------------------------------------------------------ +// this function reads the mouse for input + +static gkey read_mouse(_item_t* citem) { + + #ifdef GOLD_MOUSE + register _item_t *item; + + // if free-floating mouse cursor support is on + if(gmou.FreeCursor()) { + + // clear mouse button queue + gmou.ClearEvents(); + + // loop until a key is pressed + while(!kbxhit() and gkbd.kbuf==NULL) { + + // call the keyboard loop function + //if(gkbd.kbloop!=NULL) + //(*gkbd.kbloop)(); + + // if left button was pressed, and mouse cursor is on + // a selectable menu item, then move selection bar to + // that item, and select it. If mouse cursor is on + // a main menu item of a pull-down menu system, then + // stuff that item's selection character into the CXL + // keyboard buffer and return Esc to close the current + // pull-down menu. + gmou.GetLeftRelease(); + if(gmou.Count()) { + item = mouse_on_item(gwin.cmenu,gmou.Row(),gmou.Column()); + if(item == NULL) { + if(gwin.cmenu->menutype&M_PD) { + item = mouse_on_item(gwin.cmenu->parent,gmou.Row(),gmou.Column()); + if(item and (!(item->fmask&M_NOSEL))) { + kbput(item->schar); + return Key_Esc; + } + } + } + else { + if(!(item->fmask&M_NOSEL)) { + if(citem != item) { + pre_move(citem); + gwin.cmenu->citem = citem = item; + post_move(item); + } + return Key_Ent; + } + } + } + + // if right button was pressed, simulate pressing the Esc key + gmou.GetRightRelease(); + if(gmou.Count()) + return Key_Esc; + } + } + #endif + + // return zero - it means a key was pressed + return 0; +} + + +// ------------------------------------------------------------------ +// this function will find the menu selection to the right of current + +static _item_t * right_item(_item_t *curr) +{ + _item_t *best,*temp; + int wwidth,bpos,tpos,cpos; + + // calculate window width and current position + wwidth=gwin.cmenu->ecol - gwin.cmenu->scol + 1; + cpos=(curr->wrow * wwidth) + curr->wcol; + + // initialize best record to NULL, and best position to 32767 + best=NULL; + bpos=32767; + + // search backwards through linked list, testing items + for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) { + + // calculate position of test item + tpos=(temp->wrow*wwidth) + temp->wcol; + + // compare position of test item with best item, current item + if((tposcpos)) { + best=temp; + bpos=tpos; + } + } + + // if there wasn't a item to the right, then wrap around + if(best==NULL) + best=first_item(); + else + // see if menu selection is non-selectable + if(best->fmask&M_NOSEL) + best=right_item(best); + + // return best record + return(best); +} + + +// ------------------------------------------------------------------ +// this function finds the previous menu selection upwards + +static _item_t * up_item(_item_t *curr) +{ + _item_t *best,*temp; + int brow,bcol,tcol,crow,trow,ccol,tdist,bdist; + + // initialize best record to NULL + best = NULL; + brow = -1; + bcol = 32767; + + // calculate window column at center of current item + crow=(int)curr->wrow; + ccol=calc_center_item(curr); + + // search backwards through linked list, testing items + for(temp=gwin.cmenu->item;temp!=NULL;temp=temp->prev) { + + // calculate window column at center of test item + trow=(int)temp->wrow; + tcol=calc_center_item(temp); + + if(trowbrow) or ((trow==brow) and (tdistwrow=255; + best=up_item(temp); + throw_free(temp); + } + } + else + // see if menu selection is non-selectable + if(best->fmask&M_NOSEL) + best=up_item(best); + + // return best record + return(best); +} + + +// ------------------------------------------------------------------ + +int wmenubeg(int srow, int scol, int erow, int ecol, int btype, vattr battr, vattr wattr, VfvCP open, int menutype) { + + _menu_t* wmenu; + + // if this is a submenu, then make sure that it is under a menu item + if(gwin.mlevel>gwin.ilevel) return(gwin.werrno=W_NOITMDEF); + + // allocate memory for new menu record + if((wmenu=(_menu_t*)throw_malloc(sizeof(_menu_t)))==NULL) + return(gwin.werrno=W_ALLOCERR); + + // if menu is not a submenu, make it a new base menu record + if(!gwin.mlevel) { + if(gwin.menu!=NULL) gwin.menu->next=wmenu; + wmenu->prev=gwin.menu; + wmenu->next=NULL; + wmenu->parent=NULL; + gwin.menu=gwin.cmenu=wmenu; + } + else { + if(menutype & M_PD) + gwin.cmenu->item->fmask |= M_HASPD; // Has a pull-down menu + gwin.cmenu->item->fmask &= ~M_CLOSE; // Don't close parent menu + wmenu->parent=gwin.cmenu; + gwin.cmenu = (_menu_t*)(gwin.cmenu->item->child = wmenu); + } + + // save info in menu record + wmenu->srow=srow; + wmenu->scol=scol; + wmenu->erow=erow; + wmenu->ecol=ecol; + wmenu->btype=btype; + wmenu->battr=battr; + wmenu->loattr=battr; + wmenu->sbattr=battr; + wmenu->wattr=wattr; + wmenu->menutype=menutype; + wmenu->open=open; + wmenu->usecurr=NO; + wmenu->item=NULL; + wmenu->title = ""; + wmenu->titlepos = -1; + wmenu->titleattr = BLACK_|_BLACK; + wmenu->shadattr = DEFATTR; + wmenu->items = 0; + + // increment menu level + gwin.mlevel++; + + // return normally + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int wmenuitem(int wrow, int wcol, const char* str, char schar, int tagid, int fmask, VfvCP select, gkey hotkey, int help) { + + _item_t* witem; + + // make sure that wmenubeg() or wmenubegc() has been called + if(!gwin.mlevel) + return (gwin.werrno=W_NOMNUBEG); + + // allocate memory for new item record + witem = (_item_t*)throw_malloc(sizeof(_item_t)); + if(witem==NULL) + return (gwin.werrno=W_ALLOCERR); + + // add new menu item record to linked list + if(gwin.cmenu->item) + gwin.cmenu->item->next = witem; + witem->prev = gwin.cmenu->item; + witem->next = NULL; + gwin.cmenu->item = witem; + + // save info in item record + witem->wrow = wrow; + witem->wcol = wcol; + witem->str = str; + witem->schar = schar; + witem->tagid = tagid; + witem->fmask = fmask; + witem->select = select; + witem->hotkey = hotkey; + witem->desc = NULL; + witem->dwhdl = -1; + witem->dwrow = 0; + witem->dwcol = 0; + witem->dattr = BLACK_|_BLACK; + witem->redisp = NO; + witem->help = help; + witem->child = NULL; + witem->before = NULL; + witem->after = NULL; + + gwin.cmenu->items++; + + int border = (gwin.cmenu->btype == 5) ? 0 : 1; + + int width = 1 + (gwin.cmenu->ecol-border) - (gwin.cmenu->scol+border); + size_t _titlen = gwin.cmenu->title ? strlen(gwin.cmenu->title) : 0; + size_t _strlen = strlen(str); + size_t length = maximum_of_two(_strlen, _titlen); + if((int)length > width) + gwin.cmenu->ecol += length - width; + + if(gwin.cmenu->menutype & M_VERT) { + int height = 1 + (gwin.cmenu->erow-border) - (gwin.cmenu->srow+border); + if(gwin.cmenu->items > height) + gwin.cmenu->erow += gwin.cmenu->items - height; + } + + // set item level == menu level + gwin.ilevel = gwin.mlevel; + + // return normally + return (gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int wmenuend(int taginit, int menutype, int barwidth, int textpos, vattr textattr, vattr scharattr, vattr noselattr, vattr barattr) { + + _item_t* item; + int w_width, border, found; + + // make sure at least 1 menu item has been defined + if(not gwin.mlevel or (gwin.mlevel>gwin.ilevel)) + return(gwin.werrno=W_NOITMDEF); + + // make sure that the specified initial tagid matches the + // tagid of one of the defined menu items in this menu + for(found=NO,item=gwin.cmenu->item;item!=NULL;item=item->prev) { + if(item->tagid==taginit) { + found=YES; + break; + } + } + if(!found) return(gwin.werrno=W_INVTAGID); + + // if bar width > window width, then bar width = window width + border=(gwin.cmenu->btype==5)?0:1; + w_width=(gwin.cmenu->ecol-border)-(gwin.cmenu->scol+border)+1; + if(barwidth>w_width) barwidth=w_width; + + // add rest of menu information to menu record + gwin.cmenu->citem = NULL; + gwin.cmenu->tagcurr = taginit; + gwin.cmenu->menutype |= menutype; + gwin.cmenu->barwidth = barwidth; + gwin.cmenu->textpos = barwidth?textpos:0; + gwin.cmenu->textattr = textattr; + gwin.cmenu->scharattr = scharattr; + gwin.cmenu->noselattr = noselattr; + gwin.cmenu->barattr = barattr; + + // set current menu pointer to parent menu + if((gwin.cmenu=gwin.cmenu->parent)==NULL) gwin.cmenu=gwin.menu; + + // decrement menu and item levels + gwin.mlevel--; + gwin.ilevel--; + + // return with no error + return(gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int wmenuget() { + + int valid, pulldown=NO, menuerr, winerr, err; + _item_t* citem; + _item_t* item; + int w = -1; + gkey xch; + char ch; + static int _depth = 0; + + if (_depth == 0) + { + _overtagid = -1; + _finaltagid = -1; + } + + // make sure we have a defined menu + if(gwin.cmenu==NULL) { + gwin.werrno=W_NOMNUDEF; + return(-1); + } + + // make sure that wmenuend() was called + if(gwin.mlevel or gwin.ilevel) { + gwin.werrno=W_NOMNUEND; + return(-1); + } + + // open menu's window (unless menu is to use current window) + if(!gwin.cmenu->usecurr) { + w=whandle(); + hide_mouse_cursor_mnu(); + if(!wopen(gwin.cmenu->srow,gwin.cmenu->scol,gwin.cmenu->erow,gwin.cmenu->ecol,gwin.cmenu->btype,gwin.cmenu->battr,gwin.cmenu->wattr,gwin.cmenu->sbattr,gwin.cmenu->loattr)) + return -1; + if(gwin.cmenu->shadattr != DEFATTR) + wshadow(gwin.cmenu->shadattr); + if(gwin.cmenu->title and *gwin.cmenu->title) + wtitle(gwin.cmenu->title, gwin.cmenu->titlepos, gwin.cmenu->titleattr); + show_mouse_cursor_mnu(); + + // save environment info, call menu open + // function, then restore environment info + if(gwin.cmenu->open!=NULL) + mnu_call_func(gwin.cmenu->open); + } + + // if mouse cursor mode is on, show cursor + show_mouse_cursor_mnu(); + + // find first item in linked list + if((item=gwin.cmenu->item)!=NULL) for(;item->prev!=NULL;item=item->prev); + + // display all menu items + dispdesc=NO; + valid=NO; + while(item!=NULL) { + disp_item(item,0); + if(!(item->fmask&M_NOSEL)) valid=YES; + item=item->next; + } + dispdesc=YES; + + // make sure there is at least 1 selectable menu item + if(!valid) { + pre_exit(w,YES); + gwin.werrno=W_NOSELECT; + return(-1); + } + + // search linked list of item records for the item matching + // the last item. If there was no last item, search for + // the initial tag ID position. If no initial tag ID position + // was specified, then find the upper-leftmost menu item. + citem=NULL; + if(gwin.cmenu->menutype&M_SAVE) { + for(citem=gwin.cmenu->item;citem!=NULL;citem=citem->prev) { + if((gwin.cmenu->citem==citem) and not (citem->fmask&M_NOSEL)) + break; + } + } + if(citem==NULL) { + citem=wmenuifind(gwin.cmenu->tagcurr); + if((citem==NULL) or (citem->fmask&M_NOSEL)) citem=first_item(); + } + + // call the current menu item's 'before' + // function and display current menu item + post_move(citem); + + // main process of function + + for(;;) { + + // update current menu item and help category + gwin.cmenu->citem=citem; + gwin.help=citem->help; + + // read mouse/keyboard for keypress, then test the keypress + gwin.menu->hotkey = false; + gkbd.inmenu=true; + xch = read_mouse(citem); + citem=gwin.cmenu->citem; + if(!xch) { + xch = getxch(); + } + gkbd.inmenu=false; + + _overtagid = citem->tagid; + + switch(xch) { + + case Key_Esc: + + // if Esc checking is on, erase selection bar, + // free menu records and return to caller + if(gwin.esc or (gwin.cmenu!=gwin.menu)) { + ESCAPE_KEY: + pre_move(citem); + pre_exit(w,YES); + gwin.werrno=W_ESCPRESS; + return(-1); + } + break; + + case Key_Home: + + // hide selection bar and find upper-leftmost menu item + citem=goto_item(citem,ITM_FR); + break; + + case Key_Lft: + + // if current menu is a pull-down menu, + // then erase selection bar, free menu records, + // and return special code to caller + if(gwin.cmenu->menutype&M_PD) { + pre_move(citem); + pre_exit(w,YES); + gwin.werrno=W_NOERROR; + return(M_PREVPD); + } + + // if current menu is a horizontal menu, then hide + // selection bar and find menu item to the left + if(gwin.cmenu->menutype&M_HORZ) + citem=goto_item(citem,ITM_LT); + + // if pull-down menu flag is set, select this item + if(pulldown and (citem->child!=NULL)) + goto ENTER; + break; + + case Key_Up: + + // if current menu is a vertical menu, then hide + // selection bar and find menu item upwards + if(gwin.cmenu->menutype&(M_VERT|M_PD)) + citem=goto_item(citem,ITM_UP); + break; + + case Key_Rgt: + + // if current menu is a pull-down menu, + // then erase selection bar, free menu records, + // and return special code to caller + if(gwin.cmenu->menutype&M_PD) { + pre_move(citem); + pre_exit(w,YES); + gwin.werrno=W_NOERROR; + return(M_NEXTPD); + } + + // if current menu is a horizontal menu, then hide + // selection bar and find menu item to the right + if(gwin.cmenu->menutype&M_HORZ) + citem=goto_item(citem,ITM_RT); + + // if pulldown flag is set, then select this item + if(pulldown and (citem->child!=NULL)) + goto ENTER; + break; + + case Key_Dwn: + + // if current item has a pull-down menu, select it + if(citem->fmask&M_HASPD) + goto ENTER; + + // if current menu is a vertical menu, then hide + // selection bar and find menu item downwards + if(gwin.cmenu->menutype&(M_VERT|M_PD)) + citem=goto_item(citem,ITM_DN); + break; + + case Key_End: + + // hide selection bar and find + // lower-rightmost menu item + citem=goto_item(citem,ITM_LS); + break; + + case Key_Ent: + + ENTER: + + // if current menu item has a pull-down menu + // attached, then set the pulldown flag + if(citem->fmask&M_HASPD) + pulldown=YES; + + // display menu item with selection bar + disp_item(citem,1); + + menuerr=0; + + // if current menu item has a child menu + if(citem->child!=NULL) { + + // save environment info, process child + // menu, then restore environment info + gwin.cmenu=(_menu_t*)citem->child; + hide_mouse_cursor_mnu(); + err=whelpush(); + _depth++; + menuerr=wmenuget(); + _depth--; + winerr=gwin.werrno; + if(!err) whelpop(); + show_mouse_cursor_mnu(); + gwin.cmenu=gwin.cmenu->parent; + + // if an error was returned by + // child menu, free menu records + // and pass error code to caller + if((menuerr==-1) and (winerr!=W_ESCPRESS)) { + call_after(citem); + menuerr=winerr; + pre_exit(w,YES); + gwin.werrno=menuerr; + return(-1); + } + } + + // if the M_CLOSB feature is on, then close the menu's + // window before the selection function is called. + if(citem->fmask&M_CLOSB) close_window(w); + + // this is used as a flag to see if the selection bar's + // position has been changed by the select function. + gwin.cmenu->tagcurr=-1; + + // if current menu item has a select function, call it + if(citem->select!=NULL) + mnu_call_func(citem->select); + + // if the M_CLOSB feature is on, then free the current + // menu a before the selection function is called. + if(citem->fmask&M_CLOSB) { + call_after(citem); + _finaltagid = citem->tagid; + pre_exit(w,NO); + gwin.werrno=W_NOERROR; + return _finaltagid; + } + + // check all menu items in current menu to + // see if their redisplay flag has been set + for(item=gwin.cmenu->item;item!=NULL;item=item->prev) { + if(item->redisp) { + disp_item(item,(item==citem)); + item->redisp=NO; + } + } + + // see if selection bar position was changed by select + // function. if so, then move selection bar to new item + if(gwin.cmenu->tagcurr!=-1) { + item=wmenuifind(gwin.cmenu->tagcurr); + if((item!=NULL) and not (item->fmask&M_NOSEL)) { + pre_move(citem); + post_move(gwin.cmenu->citem=citem=item); + break; + } + } + + // if current menu item has a pull-down attached + if(citem->fmask&M_HASPD) { + + // if child menu returned previous pull-down menu + // flag, find menu item to the left and select it + if(menuerr==M_PREVPD) { + citem=goto_item(citem,ITM_LT); + if(citem->fmask&M_HASPD) goto ENTER; + break; + } + + // if child menu returned next pull-down menu + // flag, find menu item to the right and select it + if(menuerr==M_NEXTPD) { + citem=goto_item(citem,ITM_RT); + if(citem->fmask&M_HASPD) goto ENTER; + break; + } + } + + // turn off pulldown flag + pulldown=NO; + + // if child menu returned an exit-all-menus flag, + // then free menu records and pass exit-all-menus + // flag onto caller + if((menuerr==M_EXITALL) or (citem->fmask&M_CLALL)) { + disp_item(citem,1); + call_after(citem); + if(citem->fmask&M_CLALL) + if(_finaltagid == -1) + _finaltagid = citem->tagid; + pre_exit(w,YES); + gwin.werrno=W_NOERROR; + return M_EXITALL; + } + + // unless an exit-this-menu flag was returned by the + // child menu, or current item has close-menu + // specified, free menu records, and return tag + // identifier of current menu item + if((citem->child!=NULL) or (citem->select!=NULL)) + if((menuerr!=M_EXIT) and (not (citem->fmask&M_CLOSE))) + break; + call_after(citem); + _finaltagid = citem->tagid; + pre_exit(w,YES); + gwin.werrno=W_NOERROR; + return _finaltagid; + + default: + + // separate ASCII code from keypress code, if ASCII + // code is zero, then it must be an extended key + ch = char(xch & 0xFF); + if (!ch and gmnudropthrough) + { + if((xch != Key_PgDn) and (xch != Key_PgUp)) + kbput(xch); + goto ESCAPE_KEY; + } + + // scan through list of items for one that + // has a tag identifier matching keypress + valid=YES; + item=citem->next; + for(;;) { + while(item!=NULL) { + if ((g_toupper(ch)==g_toupper(item->schar)) && !(item->fmask & M_NOSEL)) + { + if (!gwin.menu->hotkey) _overtagid = item->tagid; + goto FARBREAK; + } + if(citem==item) { + valid=NO; + goto FARBREAK; + } + item=item->next; + } + for(item=gwin.cmenu->item; item->prev!=NULL; item=item->prev) {} + } + + FARBREAK: + + // if a matching tag identifier was found, + // then hide selection bar, and if quick-key + // selection is allowed, select the found menu item + if(valid) { + if(item!=citem) { + pre_move(citem); + post_move(gwin.cmenu->citem=citem=item); + } + if(!(gwin.cmenu->menutype&M_NOQS)) goto ENTER; + } + } + } +} + + +// ------------------------------------------------------------------ +// Starts a menu definition in active window + +int wmenubegc() { + + // call wmenubeg() using current window parameters + if(wmenubeg(gwin.active->srow, + gwin.active->scol, + gwin.active->erow, + gwin.active->ecol, + gwin.active->btype, + gwin.active->battr, + gwin.active->wattr, + NULL)) { + return gwin.werrno; + } + + // turn on use-current-window flag + gwin.cmenu->usecurr=YES; + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +static _item_t* search_menu(_menu_t* menu, int tagid) { + + _item_t *witem, *item; + + // do while more items in this menu + for(witem=menu->item; witem!=NULL; witem=witem->prev) { + + // if tagid of found item matches item we're + // searching for, then return that item's address + if(witem->tagid==tagid) + return witem; + + // if current item has a child menu, search it + if(witem->child!=NULL) { + item = search_menu((_menu_t*)witem->child,tagid); + if(item!=NULL) + return item; + } + } + + // return address of item found + return witem; +} + + +// ------------------------------------------------------------------ +// Finds item record in a menu structure + +_item_t* wmenuifind(int tagid) { + + _item_t* item; + + // check for existance of a menu + if(gwin.cmenu==NULL) { + gwin.werrno=W_NOMNUDEF; + return NULL; + } + + // start search process at root of menu structure + item = search_menu(gwin.menu,tagid); + + // return to caller + gwin.werrno = (item==NULL) ? W_NOTFOUND : W_NOERROR; + return item; +} + + +// ------------------------------------------------------------------ +// Adds a text description to menu item + +int wmenuitxt(int whdl, int wrow, int wcol, vattr attr, const char* str) { + + // make sure at least 1 menu item has been defined + if(!gwin.mlevel or gwin.mlevel>gwin.ilevel) + return gwin.werrno=W_NOITMDEF; + + // add description info to menu record + _item_t* citem = gwin.cmenu->item; + citem->dwhdl = whdl; + citem->dwrow = wrow; + citem->dwcol = wcol; + citem->dattr = attr; + citem->desc = str; + + // return normally + return gwin.werrno=W_NOERROR; +} + + +// ------------------------------------------------------------------ + +int wmenuiba(VfvCP before, VfvCP after) { + + // make sure at least 1 menu item has been defined + if(!gwin.mlevel or gwin.mlevel > gwin.ilevel) + return(gwin.werrno=W_NOITMDEF); + + // update menu item record + gwin.cmenu->item->before = before; + gwin.cmenu->item->after = after; + + // return normally + return (gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int wmenuidsab(int tagid) { + + struct _item_t *item; + + // check for existance of a menu + if(gwin.cmenu==NULL) + return (gwin.werrno=W_NOMNUDEF); + + // find address of requested menu item + if((item=wmenuifind(tagid))==NULL) + return gwin.werrno; + + // disable menu item by making it nonselectable + item->fmask |= M_NOSEL; + + // set menu item's redisplay flag + item->redisp = true; + + // return normally + return (gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int wmenuienab(int tagid) { + + struct _item_t *item; + + // check for existance of a menu + if(gwin.cmenu==NULL) + return (gwin.werrno=W_NOMNUDEF); + + // find address of requested menu item + if((item=wmenuifind(tagid))==NULL) + return gwin.werrno; + + // enable menu item by making it selectable + item->fmask &= (~M_NOSEL); + + // set menu item's redisplay flag + item->redisp = true; + + // return normally + return (gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ + +int wmenuinext(int tagid) { + + // see if tagid is valid + if(wmenuifind(tagid)==NULL) + return gwin.werrno; + + // set current menu's current tagid to input tagid + wmenumcurr()->tagcurr = tagid; + + // return normally + return (gwin.werrno=W_NOERROR); +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinmnub.cpp b/goldlib/gcui/gwinmnub.cpp new file mode 100644 index 0000000..7dbb7fa --- /dev/null +++ b/goldlib/gcui/gwinmnub.cpp @@ -0,0 +1,323 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Menu class. +// ------------------------------------------------------------------ + +#include +#include +#include + + +// ------------------------------------------------------------------ + +void GMnu::Init() { + + bordertype = 0; + bordercolor = BLACK_|_BLACK; + + textcolor = BLACK_|_BLACK; + quickcolor = BLACK_|_BLACK; + noselcolor = BLACK_|_BLACK; + barcolor = BLACK_|_BLACK; + shadowcolor = DEFATTR; + + title = NULL; + titlepos = TCENTER; + titlecolor = BLACK_|_BLACK; + + deschdl = -1; + descrow = 0; + desccolumn = 0; + desccolor = BLACK_|_BLACK; + + helpnumber = -1; + + beginrow = 0; + begincolumn = 0; + + menuopen = NULL; + itemmask = 0; + + escape = YES; + finaltag = -1; + status = W_NOERROR; + + depth = -1; + memset(stack, 0, sizeof(stack)); +} + + +// ------------------------------------------------------------------ + +void GMnu::SetBorder(int type, vattr color) { + + bordertype = type; + bordercolor = color; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetColor(vattr text, vattr quick, vattr nosel, vattr bar, vattr shadow) { + + textcolor = text; + quickcolor = quick; + noselcolor = nosel; + barcolor = bar; + shadowcolor = shadow; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetTitle(const char* text, vattr color, int pos) { + + title = text; + titlepos = pos; + titlecolor = color; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetTitle(const char* text) { + + title = text; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetDesc(int hdl, int row, int col, vattr color) { + + deschdl = hdl; + descrow = row; + desccolumn = col; + desccolor = color; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetPos(int row, int col, int width, int height) { + + beginrow = row; + begincolumn = col; + beginwidth = width; + beginheight = height; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetEsc(int option) { + + escape = option; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetHelp(int help) { + + helpnumber = help; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetMask(int mask) { + + itemmask = mask; +} + + +// ------------------------------------------------------------------ + +void GMnu::SetTag(int tag) { + + stack[depth].tag = tag; +} + + +// ------------------------------------------------------------------ + +void GMnu::Begin(int type) { + + bool was_horz = make_bool(stack[depth].type & M_HORZ); + depth++; + stack[depth].tag = -1; + stack[depth].type = type | M_SAVE; + stack[depth].winrow = (beginrow != -1) ? beginrow : (was_horz ? stack[depth-1].winrow+1 : stack[depth-1].winrow+stack[depth-1].itemrow); + stack[depth].wincolumn = (begincolumn != -1) ? begincolumn : (stack[depth-1].wincolumn+(was_horz?0:1)); + stack[depth].itemrow = stack[depth].itemcolumn = 0; + status = wmenubeg_( + stack[depth].winrow, + stack[depth].wincolumn, + beginheight, + beginwidth, + bordertype, + bordercolor, + textcolor, + menuopen, + stack[depth].type + ); + wmenutitshad(title, titlepos, titlecolor, shadowcolor); + beginwidth = beginheight = 0; + beginrow = begincolumn = -1; +} + + +// ------------------------------------------------------------------ + +void GMnu::End() { + + status = wmenuend(stack[depth].tag, stack[depth].type, (stack[depth].type&M_VERT)?255:0, 0, textcolor, quickcolor, noselcolor, barcolor); + depth--; + if((depth >= 0) and (stack[depth].type & M_HORZ)) + stack[depth].wincolumn += stack[depth].winwidth; + title = NULL; +} + + +// ------------------------------------------------------------------ + +extern int _overtagid; +extern int _finaltagid; + +void GMnu::Start() { + + int _prev_escape = wsetesc(escape); + wmenuget(); + finaltag = _finaltagid; + overtag = _overtagid; + wsetesc(_prev_escape); +} + + +// ------------------------------------------------------------------ + +void GMnu::Item(int tag, const char* text) { + + Item(tag, text, itemmask, NULL, 0); +} + + +// ------------------------------------------------------------------ + +void GMnu::Item(int tag, const char* text, int fmask) { + + Item(tag, text, fmask, NULL, 0); +} + + +// ------------------------------------------------------------------ + +void GMnu::Item(int tag, const char* text, VfvCP select, int fmask) { + + Item(tag, text, fmask, select, 0); +} + + +// ------------------------------------------------------------------ + +void GMnu::Item(int tag, const char* text, int fmask, VfvCP select, gkey hotkey) { + + if(stack[depth].tag == -1) + stack[depth].tag = tag; + + char shortcut = *text; + + for(_item_t* p = gwin.cmenu->item; p; p = p->prev) { + if(p->schar == shortcut) + shortcut = NUL; + } + + status = wmenuitem(stack[depth].itemrow, stack[depth].itemcolumn, text+1, shortcut, tag, fmask, select, hotkey, helpnumber); + stack[depth].winwidth = strlen(text+1); + if(stack[depth].type & M_HORZ) + stack[depth].itemcolumn += stack[depth].winwidth; + else + stack[depth].itemrow++; +} + + +// ------------------------------------------------------------------ + +void GMnu::ItemDesc(const char* text) { + + status = wmenuitxt(deschdl, descrow, desccolumn, desccolor, text); +} + + +// ------------------------------------------------------------------ + +void GMnu::ItemSep() +{ + Item(-1, " ", M_SEPAR, NULL, 0); +} + + +// ------------------------------------------------------------------ + +void GMnu::ItemFuncs(VfvCP before, VfvCP after) { + + status = wmenuiba(before, after); +} + + +// ------------------------------------------------------------------ + +void GMnu::SetNextItem(int tag) { + + status = wmenuinext(tag); +} + + +// ------------------------------------------------------------------ + +void GMnu::DisableItem(int tag) { + + status = wmenuidsab(tag); +} + + +// ------------------------------------------------------------------ + +void GMnu::EnableItem(int tag) { + + status = wmenuienab(tag); +} + + +// ------------------------------------------------------------------ + +GMnuItm* GMnu::FindItem(int tag) { + + return wmenuifind(tag); +} + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinpckf.cpp b/goldlib/gcui/gwinpckf.cpp new file mode 100644 index 0000000..46b0dd5 --- /dev/null +++ b/goldlib/gcui/gwinpckf.cpp @@ -0,0 +1,231 @@ + +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// wpickfile() - Allows user to select a file name. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// ------------------------------------------------------------------ + +static bool path_in_title, case_sensitive; +static IfcpCP open_function = NULL; +static char* cwdp; +static char* tcwdp; +static char* namextp; + + +// ------------------------------------------------------------------ +// this function is the compare function for std::sort() + +static bool compare(const std::string str1, const std::string str2) +{ + // Sort with directories first + bool dir1 = !!strchr(str1.c_str(), GOLD_SLASH_CHR); + bool dir2 = !!strchr(str2.c_str(), GOLD_SLASH_CHR); + if (dir1 && !dir2) return true; + if (!dir1 && dir2) return false; + + std::string s1 = dir1 ? str1.substr(0, str1.length()-1) : str1; + std::string s2 = dir2 ? str2.substr(0, str2.length()-1) : str2; + + int cmp; + if (case_sensitive) + cmp = strcmp(s1.c_str(), s2.c_str()); + else + { + cmp = stricmp(s1.c_str(), s2.c_str()); + if (cmp == 0) + cmp = strcmp(s1.c_str(), s2.c_str()); + } + + return (cmp < 0); +} + + +// ------------------------------------------------------------------ +// this function displays the title on the pick window border + +static void disp_title() { + + char buf[sizeof(Path)+2]; + + if(path_in_title or open_function) { + strcpy(buf, " "); + PathCopy(buf+1, cwdp); + strcat(buf, namextp); + strcat(buf, " "); + } + + if(path_in_title) { + wtitle(buf, TCENTER, gwin.active->battr); + } + + if(open_function) { + (*open_function)(buf); + } +} + + +// ------------------------------------------------------------------ + +bool wpickfile(int srow, int scol, int erow, int ecol, int btype, vattr bordattr, vattr winattr, vattr barattr, bool title, std::string &filespec, IfcpCP open, bool casesens) +{ + Path cwd, dir, namext, tcwd, path, spec; + + cwdp = cwd; + tcwdp = tcwd; + namextp = namext; + + // set static variables + open_function = open; + path_in_title = title; + case_sensitive = casesens; + + // save current working directory + getcwd(tcwd, GMAXPATH); + + // if drive was specified, change to it + char* q = strxcpy(spec, filespec.c_str(), sizeof(Path)); + + // split up input filespec into its current + // working directory and filename/extension + char* r = strrchr(q, GOLD_SLASH_CHR); + #if defined(__HAVE_DRIVES__) + if(r == NULL) + if(q[1] == ':') + r = q + 1; + #endif + if(r == NULL) { + *dir = NUL; + strcpy(namext, q); + } + else { + strins(" ", ++r, 0); + *r++ = NUL; + strcpy(dir, q); + strcpy(namext, r); + } + + bool finished; + int picked; + + do + { + // if directory was specified, change to it + if (*dir && gchdir(dir)) + { + gchdir(tcwdp); + return false; + } + + // get current working directory + getcwd(cwd, GMAXPATH); + strcpy(dir, cwd); + + // find all directories plus all files matching input filespec in + // current directory, allocating an array element for each + picked = -1; + gposixdir d(dir); + gstrarray strarr; + const gdirentry *de; + + if (d.ok) + { + while((de = d.nextentry()) != NULL) + { + const char* name = NULL; + if (de->is_directory()) + { + if(de->name != ".") { + strxmerge(path, sizeof(Path), de->name.c_str(), GOLD_SLASH_STR, NULL); + name = path; + } + } + else if(de->is_file()) + { + if(case_sensitive ? gwildmat(de->name.c_str(), namext) : gwildmati(de->name.c_str(), namext)) + name = de->name.c_str(); + } + + if (name) strarr.push_back(name); + } + } + + // sort files in array by swapping their pointers + std::sort(strarr.begin(), strarr.end(), compare); + + // let user pick file + if (strarr.size()) + { + picked = wpickstr(srow, scol, erow, ecol, btype, bordattr, winattr, barattr, strarr, 0, disp_title); + } + + if (picked == -1 or !strarr.size()) + { + gchdir(tcwdp); + return false; + } + + // see if a directory was selected. if so save + // directory name, otherwise build whole path name + const char *slash = strchr(strarr[picked].c_str(), GOLD_SLASH_CHR); + if (slash) + { + finished = false; + strcpy(dir, strarr[picked].c_str()); + r = strrchr(dir, GOLD_SLASH_CHR); + if (r) *r = NUL; + } + else { + finished = true; + PathCopy(filespec, cwd); + filespec += strarr[picked].c_str(); + } + + strarr.clear(); + } + while(not finished); // if a directory was selected, go back and do again + + gchdir(tcwd); // change back to current drive and directory + return true; // return normally +} + + +// ------------------------------------------------------------------ + diff --git a/goldlib/gcui/gwinpcks.cpp b/goldlib/gcui/gwinpcks.cpp new file mode 100644 index 0000000..0491797 --- /dev/null +++ b/goldlib/gcui/gwinpcks.cpp @@ -0,0 +1,728 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Based on CXL by Mike Smedley. +// ------------------------------------------------------------------ +// wpickstr() - Lets user pick from an array of strings. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include + +extern char m_title[]; + + +// ------------------------------------------------------------------ + +int wpickstr_tag = false; + + +// ------------------------------------------------------------------ +// define record that will hold pick window info + +struct r_t { + int numelems; + int lastelem; + int curr; + int first; + int last; + int strsperline; + int strsperwin; + int maxstrlen; + int wwidth; + int wheight; + int fillspaces; + int gapspaces; + int xtraspaces; + vattr winattr; + vattr barattr; + int scrollbar; +}; + + +// ------------------------------------------------------------------ +// this function will display the mouse +// cursor if mouse cursor mode is on + +static void show_mouse_cursor_pck() { + + #ifdef GOLD_MOUSE + if(gmou.FreeCursor()) { + gmou.ShowCursor(); + gmou.SetCursor(0,0xFFFF,((LGREY_|_LGREY)<<8)); + } + #endif +} + + +// ------------------------------------------------------------------ +// this function will hide the mouse +// cursor if mouse cursor mode is on + +static void hide_mouse_cursor_pck() { + + #ifdef GOLD_MOUSE + if(gmou.FreeCursor()) + gmou.HideCursor(); + #endif +} + + +// ------------------------------------------------------------------ +// this function updates the current item by either +// displaying or erasing the selection bar on it + +static void update_curr( const gstrarray &strarr, r_t* r, int bar) +{ + // calculate row and column string will be displayed + // at, then print out the string character-by-character + + int crow = (r->curr-r->first)/r->strsperline; + int temp = r->curr-((crow*r->strsperline)+r->first); + int ccol = (temp*r->maxstrlen)+((temp+1)*(r->gapspaces))+r->xtraspaces; + + wgotoxy(crow,ccol); + + hide_mouse_cursor_pck(); + + wprintns(crow, ccol, bar ? r->barattr : r->winattr, strarr[r->curr], r->maxstrlen); + + show_mouse_cursor_pck(); +} + + +// ------------------------------------------------------------------ + +static void update_line(const gstrarray &strarr, r_t* r, int wrow, int upcurr) +{ + int nomore = false; + int ccol = r->gapspaces + r->xtraspaces; + int celem = (wrow*r->strsperline) + r->first; + + if(celem >= r->numelems) + nomore = true; + + for(int j=0; jstrsperline; j++) { + int ccolbeg = ccol; + wprintns(wrow, ccolbeg, (upcurr and r->curr==celem) ? r->barattr : r->winattr, nomore ? "" : strarr[celem], r->maxstrlen); + ccol += r->maxstrlen; + if(++celem >= r->numelems) + nomore = true; + ccol += r->gapspaces; + } +} + + +// ------------------------------------------------------------------ +// this function will update all items in the window + +static void update_window(const gstrarray &strarr, r_t* r) +{ + hide_mouse_cursor_pck(); + for(int crow=0; crowwheight; crow++) + update_line(strarr, r, crow, 1); + show_mouse_cursor_pck(); +} + + +// ------------------------------------------------------------------ +// this function will find the element number of the +// first element on the same line as the given element + +static int e_begline(r_t* r, int elem) { + + return (elem/r->strsperline) * r->strsperline; +} + + +// ------------------------------------------------------------------ +// this function will find the first element in a +// window, using a given last element as input + +static int e_begwin(r_t* r, int lelem) { + + int beg = e_begline(r,lelem) + r->strsperline - r->strsperwin; + if(beg < 0) + beg = 0; + + return beg; +} + + +// ------------------------------------------------------------------ +// this function will find the element number of the +// last element on the same line as the given element + +static int e_endline(r_t* r, int elem) { + + int end = (((elem/r->strsperline)+1)*r->strsperline)-1; + if(end>=r->numelems) + end = r->lastelem; + + return end; +} + + +// ------------------------------------------------------------------ +// this function will find the last element in a +// window, using a given first element as input + +static int e_endwin(r_t* r, int felem) { + + int end = felem + r->strsperwin - 1; + if(end > (r->lastelem)) + end = r->lastelem; + + return end; +} + + +// ------------------------------------------------------------------ + +static void goto_item(r_t* r, const gstrarray &strarr, int elem) +{ + if(elem<0 or elem>r->lastelem) + elem = 0; + int outside = (elemfirst or elem>r->last) ? YES : NO; + if(outside == NO) + update_curr(strarr,r,0); + r->curr = elem; + if(outside) { + r->first = e_begwin(r,r->last = e_endwin(r,e_begline(r,r->curr))); + update_window(strarr,r); + } + else { + update_curr(strarr,r,1); + } +} + + +// ------------------------------------------------------------------ +// this function determines if the mouse cursor is on a item + +#ifdef GOLD_MOUSE +static int mouse_on_item(r_t* r, int mcrow, int mccol) { + + int found = -1; + int srow = gwin.active->srow; + int scol = gwin.active->scol; + int border = gwin.active->border; + + for(int i=r->first; i<=r->last; i++) { + if(mcrow==(srow+border+((i-r->first)/r->strsperline))) { + int start = scol+border+r->xtraspaces+r->gapspaces+((i%r->strsperline)*(r->maxstrlen+r->gapspaces)); + int end = start+r->maxstrlen-1; + if(mccol>=start and mccol<=end) { + found = i; + break; + } + } + } + if(found==-1 and r->scrollbar and mccol==gwin.active->ecol) { + if(mcrow==srow+1) + found=-2; + else { + if(mcrow==gwin.active->erow-1) + found=-3; + } + } + + return found; +} +#endif + + +// ------------------------------------------------------------------ + +static void page_down(const gstrarray &strarr, r_t* r) +{ + if(r->curr != r->last) { + r->curr = r->last; + update_window(strarr, r); + } + else if(r->last != (r->lastelem)) { + int i = r->curr-r->first; + r->last = e_endwin(r,r->last+1); + r->first = e_begwin(r, r->last); + if((r->curr = r->first+i) > (r->lastelem)) + r->curr -= r->strsperline; + update_window(strarr, r); + } +} + + +// ------------------------------------------------------------------ + +static void page_up(const gstrarray &strarr, r_t* r) +{ + if(r->curr != r->first) { + r->curr = r->first; + update_window(strarr, r); + } + else if(r->first) { + int i = r->curr-r->first; + r->first = e_begwin(r,r->first-1); + r->last = e_endwin(r, r->first); + r->curr = r->first+i; + update_window(strarr,r); + } +} + + +// ------------------------------------------------------------------ + +static void scroll_down(const gstrarray &strarr, r_t* r, int upcurr) +{ + if(r->first) { + hide_mouse_cursor_pck(); + if(upcurr) + update_curr(strarr,r,0); + r->first -= r->strsperline; + r->last = e_endline(r,r->last-r->strsperline); + if(upcurr>1) + r->curr -= r->strsperline; + if(r->first != e_begline(r,r->last)) + wscroll(1,SDOWN); + update_line(strarr, r, 0, (upcurr>2) ? 0 : upcurr); + show_mouse_cursor_pck(); + } +} + + +// ------------------------------------------------------------------ + +static void scroll_up(const gstrarray &strarr, r_t* r, int upcurr) +{ + if(r->last!=(r->lastelem)) { + hide_mouse_cursor_pck(); + if(upcurr) + update_curr(strarr,r,0); + r->first+=r->strsperline; + r->last=e_endline(r,r->last+1); + if(upcurr>1) + if((r->curr+r->strsperline)<=r->last) + r->curr+=r->strsperline; + if(r->first!=e_begline(r,r->last)) + wscroll(1,SUP); + update_line(strarr,r,r->wheight-1,(upcurr>2)?0:upcurr); + show_mouse_cursor_pck(); + } +} + + +// ------------------------------------------------------------------ +// this function reads the mouse for input + +static gkey read_mouse(const gstrarray & /*strarr*/, r_t* /*r*/) +{ + #ifdef GOLD_MOUSE + // if free-floating mouse cursor support is on + if(gmou.FreeCursor()) { + + // clear mouse button queue + gmou.ClearEvents(); + + // loop until a key is pressed + while(!kbxhit() and gkbd.kbuf==NULL) { + + // call the keyboard loop function, if defined + //if(gkbd.kbloop!=NULL) + //(*gkbd.kbloop)(); + + // see if the right button (Esc) was pressed + gmou.GetRightRelease(); + if(gmou.Count()) + return Key_Esc; + + // see where mouse cursor is at - if it is on a scroll bar + // or menu item, and the left button is pressed, then scroll + // menu or select item + gmou.GetStatus(); + int i = mouse_on_item(r,gmou.Row(),gmou.Column()); + switch(i) { + case -1: + gmou.ClearEvents(); + break; + case -2: + if(gmou.LeftButton()) { + scroll_down(strarr,r,3); + if(gvid->isbios()) + usleep(50); + gmou.ClearEvents(); + } + break; + case -3: + if(gmou.LeftButton()) { + scroll_up(strarr,r,3); + if(gvid->isbios()) + usleep(50); + gmou.ClearEvents(); + } + break; + default: + gmou.GetLeftRelease(); + if(gmou.Count()) { + r->curr = i; + return Key_Ent; + } + } + } + } + #endif + + // return zero - it means a key was pressed + return 0; +} + + +// ------------------------------------------------------------------ + +int wpickstr(int srow, int scol, int erow, int ecol, int btype, vattr bordattr, vattr winattr, vattr barattr, gstrarray &strarr, int initelem, VfvCP open) +{ + int outside; + gkey xch; + char ch; + r_t r; + + int quickpos = (strarr[0][0] == ' ') ? 1 : 0; + + // go through input array and determine the longest + // string, and count the number of elements in the array + + size_t maxlen = strlen(m_title); + + gstrarray::const_iterator it = strarr.begin(); + gstrarray::const_iterator end = strarr.end(); + for (; it != end; it++) + { + size_t len; + if ((len = it->length()) > maxlen) + { + maxlen = len; + } + } + + r.maxstrlen = maxlen; + r.numelems = strarr.size(); + r.lastelem = r.numelems - 1; + r.winattr = winattr; + r.barattr = barattr; + + // see if window is to have a border + int border = (btype==5) ? NO : YES; + + // if ecol == -1 then adjust it to conform to length of longest string + if(ecol==-1) + ecol = scol+border+r.maxstrlen+border-1; + + // calculate window area width and height + r.wwidth = (ecol-border)-(scol+border)+1; + r.wheight = (erow-border)-(srow+border)+1; + + // make sure longest string can fit in window + if(r.maxstrlen > r.wwidth) + r.maxstrlen = r.wwidth; + + // open window which strings will reside in + hide_mouse_cursor_pck(); + if(!wopen(srow,scol,erow,ecol,btype,bordattr,winattr,bordattr)) + return -1; + + // if mouse cursor mode is on and window has a border, + // display scroll indicator arrows on right window border + #ifdef GOLD_MOUSE + if(gmou.FreeCursor() and (btype!=5) and ((srow+2) < erow)) { + vputc(srow+1,ecol,bordattr,(char) 24); + vputc(erow-1,ecol,bordattr,(char) 25); + r.scrollbar=true; + } + else { + #endif + r.scrollbar=false; + #ifdef GOLD_MOUSE + } + #endif + show_mouse_cursor_pck(); + + // if an open function has been specified, then call it + if(open!=NULL) + open(); + + // if mouse cursor mode is on, then turn on mouse cursor + show_mouse_cursor_pck(); + + // calculate how many strings can fit into 1 window line, number of + // filler spaces needed per window line, number of spaces per gap in + // between strings, number of extra spaces to add to first gap, and + // number of strings that can fit inside the window + r.strsperline = (r.wwidth-2)/(r.maxstrlen+2); + if(!r.strsperline) + r.strsperline++; + r.fillspaces = r.wwidth-(r.strsperline*r.maxstrlen); + r.gapspaces = r.fillspaces/(r.strsperline+1); + r.xtraspaces = (r.fillspaces%(r.strsperline+1))/2; + r.strsperwin = r.strsperline*r.wheight; + + // initialize first, last, and current elements + r.curr = r.first = 0; + r.last = (r.numelemsr.last) + scroll_up(strarr,&r,((r.curr+r.strsperline)>r.lastelem) ? 0 : 2); + else { + update_curr(strarr,&r,0); + r.curr+=r.strsperline; + update_curr(strarr,&r,1); + } + break; + + case Key_PgUp: + + // move up 1 page. adjust position if at 1st element + page_up(strarr,&r); + break; + + case Key_PgDn: + + // move down 1 page. adjust position if at last element + page_down(strarr,&r); + break; + + case Key_Home: + + // set position to 1st element + if(r.curr) { + if((outside=r.first)==NO) + update_curr(strarr,&r,0); + r.first=r.curr=0; + if(outside) { + r.last=e_endwin(&r,r.first); + update_window(strarr,&r); + } + else { + update_curr(strarr,&r,1); + } + } + break; + + case Key_End: + + // set position to last element + if(r.curr!=r.lastelem) { + if((outside=(r.last<(r.lastelem))?YES:NO)==NO) + update_curr(strarr,&r,0); + r.last=r.curr=r.lastelem; + if(outside) { + r.first=e_begwin(&r,r.last); + update_window(strarr,&r); + } + else { + update_curr(strarr,&r,1); + } + } + break; + + default: + + // if not an extended keypress, then search from current + // position for the item that begins with the same ASCII + // character as the keypress. If not found after current + // position, search from the beginning for a match + ch = (char)g_toupper(char(xch & 0xFF)); + if (!ch) break; + + size_t i; + for (i = r.curr + 1; i < r.numelems; i++) + { + if (ch == g_toupper(strarr[i][quickpos])) + break; + } + + if (i == r.numelems) + { + for (i = 0; i < r.curr; i++) + { + if (ch == g_toupper(strarr[i][quickpos])) + break; + } + + if (i == r.curr) continue; + } + + // a matching ASCII character was found. set position + // to matching element, adjusting window if necessary + goto_item(&r, strarr, i); + } + } +} /* wpickstr() */ + + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinpick.cpp b/goldlib/gcui/gwinpick.cpp new file mode 100644 index 0000000..57215d5 --- /dev/null +++ b/goldlib/gcui/gwinpick.cpp @@ -0,0 +1,528 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Class gwinpick - Pick engine. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include + + +// ------------------------------------------------------------------ + +gwinpick::gwinpick() { + + // memset(this, 0, sizeof(gwinpick)); WHAT!?!?! ARE YOU NUTS? + + key = 0; + keyok = false; + ypos = xpos = ylen = xlen = 0; + btype = 0; + battr = wattr = tattr = sattr = hattr = loattr = sbattr = BLACK_|_BLACK; + title = NULL; + helpcat = 0; + maximum_index = minimum_index = maximum_position = index = position = 0; + aborted = listwrap = false; + direction = 0; + replylinkfloat = 0; + +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_up() { + + bool done; + + do { + if(index > minimum_index) { + display_line(); + if(position) + position--; + else + scroll(SDOWN); + index--; + if((done = is_selectable(index))==true) + update_cursor(); + } + else { + if(listwrap) + cursor_last(); + else if(not is_selectable(index)) + cursor_down(); + done = true; + } + } while(not done); + direction = -1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_down() { + + bool done; + + do { + if(index < maximum_index) { + display_line(); + index++; + if(position < maximum_position) + position++; + else + scroll(SUP); + + if((done = is_selectable(index))!=false) + update_cursor(); + } + else { + if(listwrap) + cursor_first(); + else if(not is_selectable(index)) + cursor_up(); + done = true; + } + } while(not done); + direction = 1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_pageup() { + + uint i = index - position; + + while(not is_selectable(i)) i++; + + uint min = i + position - index; + + if(position > min) { + display_line(); + index = i; + position = min; + update_cursor(); + } + else if(index > min) { + i = maximum_position - min + position; + index -= (index >= i) ? i : index; + position = 0; + display_page(); + if(not is_selectable(index)) + cursor_down(); + } + + direction = -1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_pagedown() { + + uint max_index = index + maximum_position - position; + + if(max_index > maximum_index) max_index = maximum_index; + while(not is_selectable(max_index)) --max_index; + + uint max_position = max_index - index + position; + + if(position < max_position) { + if(index == max_index) { + if(maximum_position < maximum_index) { + position = maximum_position; + index = maximum_index; + display_page(); + update_cursor(); + } + } + else if(max_index >= max_position) { + display_line(); + position = max_position; + index = max_index; + update_cursor(); + } + else if(position != maximum_position) { + display_line(); + index += maximum_position-position; + position = maximum_position; + update_cursor(); + } + } + else if(index < maximum_index) { + if(index+maximum_position+(maximum_position - max_position)> maximum_index) { + position = maximum_index - index; + index = maximum_index; + } + else { + index += maximum_position + (maximum_position - max_position); + position = maximum_position; + } + display_page(); + } + + if(not is_selectable(index)) + cursor_up(); + + direction = 1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_first() { + + uint min_select = minimum_index; + + while(not is_selectable(min_select)) + min_select++; + + if(index > min_select) { + if(index <= position) { + display_line(); + index = position = min_select; + update_cursor(); + } + else { + index = position = min_select; + display_page(); + } + } + + direction = -1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_last() { + + uint max_select = maximum_index; + + while(not is_selectable(max_select)) + max_select--; + + if(index < max_select) { + if(index + (maximum_position-position) >= maximum_index) { + display_line(); + position += max_select - index; + index = max_select; + update_cursor(); + } + else { + position = (maximum_index-index) < maximum_position ? maximum_index-index : maximum_position; + position -= maximum_index - max_select; + index = max_select; + display_page(); + } + } + else if(position < maximum_position) { + if(maximum_position < maximum_index) { + position = maximum_position + max_select - maximum_index; + index = max_select; + display_page(); + } + } + + direction = 1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_scroll_up() { + + uint oldidx = index; + do { + if(index - position) + index--; + else + while((not is_selectable(index)) and (index < maximum_index)) + index++; + } while(not is_selectable(index)); + if(index != oldidx) + display_page(); + + direction = -1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::cursor_scroll_down() { + + uint oldidx = index; + if(index != maximum_index) { + do { + if(index < maximum_index) + index++; + else + while((not is_selectable(--index)) and (index > minimum_index)) + ; + } while(not is_selectable(index)); + } + if(index!=oldidx) + display_page(); + + direction = 1; +} + + +// ------------------------------------------------------------------ + +void gwinpick::display_line(bool bar) { + + print_line(index, position, bar); +} + + +// ------------------------------------------------------------------ + +void gwinpick::display_page() { + + if(index > position) + index -= position; + else + index = 0; + + register uint m = maximum_index-index; + + uint n; + + if (replylinkfloat) + { + if (h_offset == new_hoffset) + { + for (n=0; n<=maximum_position and n<=m; n++) + if (position == n) + print_line(index+n, n, true); + } + + h_offset = new_hoffset; + } + + for(n=0; n<=maximum_position and n<=m; n++) + print_line(index+n, n, (position == n)); + + if(n < ylen) + wputx(n, 0, battr|ACSET, _box_table(btype,1), xlen); + + for(++n; n maximum_position) ? 0 : (maximum_position - botroom); + break; + case LIST_NEARTOP: + { + uint room; + uint toproom = index; + if(toproom > (maximum_position/4)) { + if(botroom > (maximum_position/4)) + room = maximum_position/4; + else if(botroom) + room = maximum_position - botroom; + else + room = maximum_position; + } + else + room = toproom; + position = room; + } + break; + case LIST_MIDDLE: + { + uint room; + uint toproom = index; + if(toproom > (maximum_position/2)) { + if(botroom > (maximum_position/2)) + room = maximum_position/2; + else if(botroom) + room = maximum_position - botroom; + else + room = maximum_position; + } + else + room = toproom; + position = room; + } + break; + case LIST_NEARBOTTOM: + { + uint room; + uint toproom = index; + if(toproom > 3*(maximum_position/4)) { + if(botroom > 3*(maximum_position/4)) + room = 3*(maximum_position/4); + else if(botroom) + room = maximum_position - botroom; + else + room = maximum_position; + } + else + room = toproom; + position = room; + } + break; + case LIST_BOTTOM: + position = maximum_position; + break; + } + update(); +} + + +// ------------------------------------------------------------------ + +int gwinpick::run_picker() { + + #ifdef GOLD_MOUSE + gmou.HideCursor(); + #endif + + // Open and initialize + + open(); + if(helpcat) + whelppcat(helpcat); + + if(not is_selectable(index)) + cursor_down(); + + do { + + do_delayed(); + + #ifdef GOLD_MOUSE + gmou.ShowCursor(); + #endif + + keyok = true; + + do { + key = getxchtick(); + if(key == Key_Tick) + handle_key(); + } while(key == Key_Tick); + + #ifdef GOLD_MOUSE + gmou.HideCursor(); + #endif + + keyok = default_handle_key(); + + if (replylinkfloat && (h_offset != new_hoffset)) + display_page(); + + } while(keyok); + + #ifdef GOLD_MOUSE + gmou.HideCursor(); + #endif + + // Close and clean + if(helpcat) + whelpop(); + close(); + + #ifdef GOLD_MOUSE + gmou.ShowCursor(); + #endif + + return 0; +} + + +// ------------------------------------------------------------------ + diff --git a/goldlib/gcui/gwinpick.h b/goldlib/gcui/gwinpick.h new file mode 100644 index 0000000..1e7b003 --- /dev/null +++ b/goldlib/gcui/gwinpick.h @@ -0,0 +1,130 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Pick engine (declarations). +// ------------------------------------------------------------------ + +#ifndef __gwinpick_h +#define __gwinpick_h + + +// ------------------------------------------------------------------ + +#include + + +// ------------------------------------------------------------------ +// Constants + +const int PICK_DISP = 0; +const int PICK_BAR = 1; + +const int LIST_BOTTOM = -2; +const int LIST_NEARBOTTOM = -1; +const int LIST_MIDDLE = 0; +const int LIST_NEARTOP = 1; +const int LIST_TOP = 2; + + +// ------------------------------------------------------------------ + +class gwinpick { + +private: + +protected: + + gkey key; + bool keyok; + uint new_hoffset; + uint h_offset; + bool replylinkfloat; // in derived classes set this with CFG->replylinkfloat + // before call display_page() and run_picker() + + void cursor_up(); + void cursor_down(); + void cursor_pageup(); + void cursor_pagedown(); + void cursor_first(); + void cursor_last(); + void cursor_scroll_up(); + void cursor_scroll_down(); + + void update_cursor(); + + void display_line(bool bar=false); + void display_page(); + bool default_handle_key(); + + inline void update() { display_page(); }; + +public: + + uint ypos; // Window Starting Row + uint xpos; // Window Starting Column + uint ylen; // Window Height + uint xlen; // Window Width + int btype; // Window Border Type + vattr battr; // Window Border Color + vattr wattr; // Window Color + vattr tattr; // Window Title Color + vattr sattr; // Window Selection Bar Color + vattr hattr; // Window Highlight Color + vattr loattr; // Window LoAttr Color + vattr sbattr; // Window Scrollbar Color + const char* title; // Window Title + int helpcat; // Window Help Category + uint maximum_index; // List Entries - 1 + uint minimum_index; // Minimum index in the list + uint maximum_position; // Display Pos + uint index; // List Index + uint position; // Display Pos + bool aborted; // True if aborted + bool listwrap; // True if wrap-around is supported + int direction; // 1 if next, -1 if previous + + virtual void open(); // Called after window is opened + virtual void close(); // Called after window is closed + virtual void precursor(); // Called before any cursor movement + virtual void do_delayed(); // Called after a delay + virtual void print_line(uint idx, uint pos, bool isbar) = 0; + virtual void scroll(int where); // Scroll page + virtual bool handle_key(); // Handles keypress + virtual bool is_selectable(uint idx); // returns true if selectable + + void display_bar() { display_line(true); } + void center(int listmode); + + int run_picker(); + + gwinpick(); + virtual ~gwinpick() { }; +}; + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinput.h b/goldlib/gcui/gwinput.h new file mode 100644 index 0000000..bba3d1a --- /dev/null +++ b/goldlib/gcui/gwinput.h @@ -0,0 +1,236 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Class gwinput: Input form and field editing (declarations). +// ------------------------------------------------------------------ + +#ifndef __gwinput_h +#define __gwinput_h + + +// ------------------------------------------------------------------ + +#include + + +// ------------------------------------------------------------------ + +class gwinput { + +public: + + class field { + + public: + + gwinput* form; + + int pos; + int max_pos; + vattr attr; + bool fill_acs; + vchar fill; + int entry; + + char* buf; + int buf_left_pos; + int buf_end_pos; + int buf_pos; + int buf_len; + + std::string& destination; + + int id; + int row; + int column; + int max_column; + int conversion; + int entry_mode; + + field* prev; + field* next; + + field(gwinput* iform, int idnum, int wrow, int wcol, int field_width, std::string& dest, int dest_size, int cvt, int mode); + ~field(); + + bool visible(); + + void move_left(); + void move_right(); + + bool left(); + bool right(); + bool left_word(); + bool right_word(); + bool delete_left(); + bool delete_char(); + bool delete_word(bool left); + bool insert_char(char ch); + bool overwrite_char(char ch); + bool home(); + bool end(); + + void update(); + void activate(); + void deactivate(); + + void restore(); + void commit(); + + void convert(); + bool adjust_mode(); + void conditional(); + + void move_cursor(); + void draw(int from_pos=0); + + void clear_field(); + + void clipboard_paste(); + void clipboard_copy(); + }; + + field* first_field; + field* current; + + enum { + entry_new, + entry_update, + entry_conditional, + entry_noedit + }; + + enum { + cvt_none, + cvt_lowercase, + cvt_uppercase, + cvt_mixedcase + }; + + vattr idle_attr; + vattr active_attr; + vattr edit_attr; + bool fill_acs; + + vchar idle_fill; + vchar active_fill; + vchar edit_fill; + + int insert_mode; + + int done; + int dropped; + + int start_id; + + bool cursor_was_hidden; + + gwindow &window; + + gwinput(gwindow &w); + virtual ~gwinput(); + + void setup(vattr i_attr, vattr a_attr, vattr e_attr, vchar fill, bool fill_acs); + + void add_field(int idnum, int wrow, int wcol, int field_width, std::string& dest, int dest_size, int cvt=gwinput::cvt_none, int mode=gwinput::entry_conditional); + + bool first(int id=0); + bool next(); + bool previous(); + bool last(); + + bool first_visible(); + bool next_visible(); + bool previous_visible(); + bool last_visible(); + + bool move_to(int wrow, int wcol); + + field* field_at(int wrow, int wcol); + field* get_field(int id); + + void draw_all(); + void reload_all(); + void show_cursor(); + + void drop_form(); + void form_complete(); + void field_complete(); + void go_next_field(); + void go_previous_field(); + void go_up(); + void go_down(); + void go_left(); + void go_right(); + void delete_left(); + void delete_char(); + void go_field_begin(); + void go_field_end(); + void go_form_begin(); + void go_form_end(); + void toggle_insert(); + void restore_field(); + void delete_left_word(); + void delete_right_word(); + void go_left_word(); + void go_right_word(); + void enter_char(char ch); + + void prepare_form(); + void finish_form(); + + void clear_field(); + + void clipboard_cut(); + void clipboard_paste(); + void clipboard_copy(); + + bool handle_key(gkey key); + + // These are supposed to be overridden by the inheriting class + virtual bool handle_other_keys(gkey& key); + virtual bool validate(); + virtual void before(); + virtual void after(); +}; + + +// ------------------------------------------------------------------ + +class gwinput2 : public gwinput { + +public: + + gwinput2(gwindow &w) : gwinput(w) { } + + bool run(int helpcat); +}; + + +// ------------------------------------------------------------------ + +#endif + +// ------------------------------------------------------------------ diff --git a/goldlib/gcui/gwinput2.cpp b/goldlib/gcui/gwinput2.cpp new file mode 100644 index 0000000..254bd94 --- /dev/null +++ b/goldlib/gcui/gwinput2.cpp @@ -0,0 +1,1221 @@ +// This may look like C code, but it is really -*- C++ -*- + +// ------------------------------------------------------------------ +// The Goldware Library +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307, USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// GCUI: Golded+ Character-oriented User Interface. +// Class gwinput: Input form and field editing. +// ------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include + + +// ------------------------------------------------------------------ + +gwinput::gwinput(gwindow &w) : window(w) { + + first_field = current = NULL; + fill_acs = false; + idle_attr = active_attr = edit_attr = LGREY_|_BLACK; + idle_fill = active_fill = edit_fill = ' '; + insert_mode = true; + done = dropped = false; + start_id = 0; +} + + +// ------------------------------------------------------------------ + +gwinput::~gwinput() { + + field* current = first_field; + if(current) { + do { + field* junk = current; + current = current->next; + delete junk; + } while(current); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::setup(vattr i_attr, vattr a_attr, vattr e_attr, vchar fill, bool f_acs) { + + idle_attr = i_attr; + active_attr = a_attr; + edit_attr = e_attr; + fill_acs = f_acs; + active_fill = edit_fill = fill; +} + + +// ------------------------------------------------------------------ + +bool gwinput::validate() { + + return true; +} + + +// ------------------------------------------------------------------ + +void gwinput::before() { + + current->activate(); +} + + +// ------------------------------------------------------------------ + +void gwinput::after() { + + current->deactivate(); +} + + +// ------------------------------------------------------------------ + +void gwinput::add_field(int idnum, int wrow, int wcol, int field_width, std::string& dest, int dest_size, int cvt, int mode) { + + field* fld = new field(this, idnum, wrow, wcol, field_width, dest, dest_size, cvt, mode); + throw_new(fld); + if(current) { + current->next = fld; + fld->prev = current; + current = fld; + } + else { + first_field = current = fld; + } +} + + +// ------------------------------------------------------------------ + +bool gwinput::move_to(int wrow, int wcol) { + + field* f = field_at(wrow, wcol); + if(f) { + after(); + current = f; + before(); + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +gwinput::field* gwinput::field_at(int wrow, int wcol) { + + field* here = first_field; + do { + if(here->row == wrow) + if(in_range(wcol, here->column, here->max_column)) + return here; + here = here->next; + } while(here); + return NULL; +} + + +// ------------------------------------------------------------------ + +gwinput::field* gwinput::get_field(int id) { + + field* here = first_field; + do { + if(here->id == id) + return here; + here = here->next; + } while(here); + return NULL; +} + + +// ------------------------------------------------------------------ + +void gwinput::draw_all() { + + first(); + do { + current->draw(); + } while(next()); +} + + +// ------------------------------------------------------------------ + +void gwinput::reload_all() { + + first(); + do { + if(current->entry == gwinput::entry_new) + *current->buf = NUL; + else + strxcpy(current->buf, current->destination.c_str(), current->buf_len+1); + current->convert(); + current->buf_end_pos = strlen(current->buf); + current->draw(); + } while(next()); +} + + +// ------------------------------------------------------------------ + +bool gwinput::first_visible() { + + if(first()) { + if(not current->visible()) + if(next_visible()) + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::next_visible() { + + field* here = current; + while(here->next) { + here = here->next; + if(here->visible()) { + current = here; + return true; + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::previous_visible() { + + field* here = current; + while(here->prev) { + here = here->prev; + if(here->visible()) { + current = here; + return true; + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::last_visible() { + + if(last()) { + if(not current->visible()) + if(previous_visible()) + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::first(int id) { + + if(first_field) { + current = first_field; + if(id) + while(current->id != id) + next(); + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::next() { + + if(current->next) { + current = current->next; + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::previous() { + + if(current->prev) { + current = current->prev; + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::last() { + + if(first_field) { + current = first_field; + while(next()) + ; + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +void gwinput::show_cursor() { + + if(insert_mode) + vcursmall(); + else + vcurlarge(); +} + + +// ------------------------------------------------------------------ + +void gwinput::drop_form() { + + after(); + done = true; + dropped = true; +} + + +// ------------------------------------------------------------------ + +void gwinput::form_complete() { + + after(); + done = true; +} + + +// ------------------------------------------------------------------ + +void gwinput::field_complete() { + + if(validate()) { + after(); + if(not next_visible()) { + done = true; + return; + } + before(); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::go_next_field() { + + after(); + if(not next_visible()) + first_visible(); + before(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_previous_field() { + + after(); + if(not previous_visible()) + last_visible(); + before(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_up() { + + int min_column = current->column; + int max_column = current->max_column; + int check_row = current->row - 1; + int check_column = current->column + current->pos; + for(int r=check_row; r>=0; r--) { + int c; + for(c=check_column; c<=max_column; c++) { + if(move_to(r, c)) + return; + } + for(c=check_column-1; c>=min_column; c--) { + if(move_to(r, c)) + return; + } + } +} + + +// ------------------------------------------------------------------ + +void gwinput::go_down() { + + int max_row = window.height() - (window.has_border() ? 2 : 0) - 1; + int min_column = current->column; + int max_column = current->max_column; + int check_row = current->row + 1; + int check_column = current->column + current->pos; + for(int r=check_row; r<=max_row; r++) { + int c; + for(c=check_column; c<=max_column; c++) { + if(move_to(r, c)) + return; + } + for(c=check_column-1; c>=min_column; c--) { + if(move_to(r, c)) + return; + } + } +} + + +// ------------------------------------------------------------------ + +void gwinput::go_left() { + + if(not current->left()) + go_previous_field(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_right() { + + if(not current->right()) + go_next_field(); +} + + +// ------------------------------------------------------------------ + +void gwinput::delete_left() { + + current->delete_left(); +} + + +// ------------------------------------------------------------------ + +void gwinput::delete_char() { + + current->delete_char(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_field_begin() { + + current->home(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_field_end() { + + current->end(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_form_begin() { + + after(); + first_visible(); + before(); + current->home(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_form_end() { + + after(); + last_visible(); + before(); + current->end(); +} + + +// ------------------------------------------------------------------ + +void gwinput::toggle_insert() { + + insert_mode ^= true; + show_cursor(); +} + + +// ------------------------------------------------------------------ + +void gwinput::restore_field() { + + current->restore(); +} + + +// ------------------------------------------------------------------ + +void gwinput::delete_left_word() { + + current->delete_word(true); +} + + +// ------------------------------------------------------------------ + +void gwinput::delete_right_word() { + + current->delete_word(false); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_left_word() { + + current->left_word(); +} + + +// ------------------------------------------------------------------ + +void gwinput::go_right_word() { + + current->right_word(); +} + + +// ------------------------------------------------------------------ + +void gwinput::enter_char(char ch) { + + if(ch) { + if(insert_mode) + current->insert_char(ch); + else + current->overwrite_char(ch); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::prepare_form() { + + cursor_was_hidden = vcurhidden(); + draw_all(); + first(start_id); + before(); + show_cursor(); +} + + +// ------------------------------------------------------------------ + +void gwinput::finish_form() { + + if(not dropped) { + first(); + do { + current->commit(); + } while(next()); + } + + if(cursor_was_hidden) + vcurhide(); +} + + +// ------------------------------------------------------------------ + +void gwinput::clear_field() { + + current->clear_field(); +} + + +// ------------------------------------------------------------------ + +void gwinput::clipboard_cut() { + + current->clipboard_copy(); + current->clear_field(); +} + + +// ------------------------------------------------------------------ + +void gwinput::clipboard_paste() { + + if(insert_mode) + current->clipboard_paste(); + else { + current->clear_field(); + current->clipboard_paste(); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::clipboard_copy() { + + current->clipboard_copy(); +} + + +// ------------------------------------------------------------------ + +bool gwinput::handle_other_keys(gkey&) { + + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::handle_key(gkey key) { + + switch(key) { + case Key_Esc: drop_form(); break; + case Key_C_Ent: form_complete(); break; + case Key_Ent: field_complete(); break; + case Key_Tab: go_next_field(); break; + case Key_S_Tab: go_previous_field(); break; + case Key_Up: go_up(); break; + case Key_Dwn: go_down(); break; + case Key_Lft: go_left(); break; + case Key_Rgt: go_right(); break; + case Key_BS: delete_left(); break; + case Key_Del: delete_char(); break; + case Key_Home: go_field_begin(); break; + case Key_End: go_field_end(); break; + case Key_C_Home: go_form_begin(); break; + case Key_C_End: go_form_end(); break; + case Key_Ins: toggle_insert(); break; + case Key_A_BS: // fall through + case Key_C_R: restore_field(); break; + case Key_C_BS: delete_left_word(); break; + case Key_C_T: delete_right_word(); break; + case Key_C_Lft: go_left_word(); break; + case Key_C_Rgt: go_right_word(); break; +#if !defined(__UNIX__) || defined(__USE_NCURSES__) + case Key_S_Ins: // fall through +#endif + case Key_C_V: clipboard_paste(); break; +#if !defined(__UNIX__) || defined(__USE_NCURSES__) + case Key_S_Del: // fall through +#endif + case Key_C_X: clipboard_cut(); break; +#if !defined(__UNIX__) || defined(__USE_NCURSES__) + case Key_C_Ins: // fall through +#endif + case Key_C_C: clipboard_copy(); break; +#if !defined(__UNIX__) || defined(__USE_NCURSES__) + case Key_C_Del: // fall through +#endif + case Key_C_Y: // fall through + case Key_C_D: clear_field(); break; + default: + if(not handle_other_keys(key)) + enter_char(KCodAsc(key)); + } + + return not done; +} + + +// ------------------------------------------------------------------ + +gwinput::field::field(gwinput* iform, int idnum, int wrow, int wcol, int field_width, std::string& dest, int dest_size, int cvt, int mode) + : destination(dest) +{ + prev = next = NULL; + pos = buf_pos = buf_left_pos = 0; + + form = iform; + id = idnum; + row = wrow; + column = wcol; + max_pos = field_width - 1; + max_column = wcol + max_pos; + buf_len = dest_size - 1; + buf = new char[dest_size]; throw_new(buf); + conversion = cvt; + entry = entry_mode = mode; + attr = form->idle_attr; + fill = form->idle_fill; + fill_acs = form->fill_acs; + + if(entry == gwinput::entry_new) + *buf = NUL; + else + strxcpy(buf, dest.c_str(), dest_size); + convert(); + buf_end_pos = strlen(buf); +} + + +// ------------------------------------------------------------------ + +gwinput::field::~field() { + + delete[] buf; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::visible() { + + return max_pos != -1; +} + + +// ------------------------------------------------------------------ + +void gwinput::field::convert() { + + switch(conversion) { + case gwinput::cvt_lowercase: + strlwr(buf); + break; + case gwinput::cvt_uppercase: + strupr(buf); + break; + case gwinput::cvt_mixedcase: + struplow(buf); + break; + } +} + + +// ------------------------------------------------------------------ + +void gwinput::field::update() { + + buf_end_pos = strlen(buf); + end(); +} + + +// ------------------------------------------------------------------ + +void gwinput::field::activate() { + + buf_end_pos = strlen(buf); + entry = entry_mode; + if(entry == gwinput::entry_conditional or entry == gwinput::entry_noedit) { + attr = form->active_attr; + fill = form->active_fill; + int entry_bak = entry; + entry = gwinput::entry_update; // cheat adjust_mode() in end() + end(); + entry = entry_bak; + } + else { + // 0 == entry_new, 1 == entry_update + entry ? end() : home(); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::field::deactivate() { + + fill = form->idle_fill; + attr = form->idle_attr; + draw(); +} + + +// ------------------------------------------------------------------ + +void gwinput::field::restore() { + + std::string tmp(buf); + strxcpy(buf, destination.c_str(), buf_len+1); + destination = tmp; + convert(); + activate(); +} + + +// ------------------------------------------------------------------ + +void gwinput::field::commit() { + + destination = buf; +} + + +// ------------------------------------------------------------------ + +void gwinput::field::move_cursor() { + + form->window.move_cursor(row, column+pos); +} + + +// ------------------------------------------------------------------ + +void gwinput::field::draw(int from_pos) { + + if(visible()) + form->window.printns(row, column+from_pos, attr, buf+buf_left_pos+from_pos, 1+max_pos-from_pos, fill, attr | (fill_acs ? ACSET : 0)); +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::adjust_mode() { + + if(entry != gwinput::entry_update and entry != gwinput::entry_noedit) { + entry = gwinput::entry_update; + attr = form->edit_attr; + fill = form->edit_fill; + return true; + } + return false; +} + + +// ------------------------------------------------------------------ + +void gwinput::field::conditional() { + + if(entry == gwinput::entry_conditional) { + clear_field(); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::field::move_left() { + + buf_pos--; + if(pos > 0) { + pos--; + move_cursor(); + } + else { + buf_left_pos--; + draw(); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::field::move_right() { + + buf_pos++; + if(pos < max_pos) { + pos++; + move_cursor(); + } + else { + buf_left_pos++; + draw(); + } +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::left() { + + if(adjust_mode()) + draw(); + + if(entry != gwinput::entry_noedit) { + if(buf_pos > 0) { + move_left(); + return true; + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::right() { + + if(adjust_mode()) { + draw(); + return true; + } + + if(entry != gwinput::entry_noedit) { + if(buf_pos < buf_end_pos) { + move_right(); + return true; + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::left_word() { + + if(adjust_mode()) + draw(); + + if(entry != gwinput::entry_noedit) { + if(buf_pos > 0) { + move_left(); + if(not isxalnum(buf[buf_pos])) { + while(not isxalnum(buf[buf_pos]) and (buf_pos > 0)) + move_left(); + while(isxalnum(buf[buf_pos]) and (buf_pos > 0)) + move_left(); + } + else { + while(isxalnum(buf[buf_pos]) and (buf_pos > 0)) + move_left(); + } + + if(buf_pos != 0) + move_right(); + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::right_word() { + + if(adjust_mode()) + draw(); + + if(entry != gwinput::entry_noedit) { + if(buf_pos < buf_end_pos) { + move_right(); + if(not isxalnum(buf[buf_pos])) { + while(not isxalnum(buf[buf_pos]) and ((buf_pos+1) <= buf_end_pos)) + move_right(); + } + else { + while(isxalnum(buf[buf_pos]) and ((buf_pos+1) <= buf_end_pos)) + move_right(); + while(not isxalnum(buf[buf_pos]) and ((buf_pos+1) <= buf_end_pos)) + move_right(); + } + return true; + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::delete_left() { + + if(adjust_mode()) + draw(); + + if(entry != gwinput::entry_noedit) { + if(buf_pos > 0) { + left(); + return delete_char(); + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::delete_char() { + + if(adjust_mode()) + draw(); + + if(entry != gwinput::entry_noedit) { + if(buf_pos < buf_end_pos) { + buf_end_pos--; + memmove(buf+buf_pos, buf+buf_pos+1, buf_len-buf_pos); + draw(pos); + move_cursor(); + return true; + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::delete_word(bool left) { + + if(adjust_mode()) + draw(); + + if(entry != gwinput::entry_noedit) { + + bool state = make_bool(isspace(buf[buf_pos-((int) left)])); + + while(left ? buf_pos > 0 : buf_pos < buf_end_pos) { + left ? delete_left() : delete_char(); + + if(make_bool(isspace(buf[buf_pos-((int) left)])) != state) + break; + } + return true; + + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::insert_char(char ch) { + + if(entry != gwinput::entry_noedit) { + + conditional(); + + if(buf_end_pos < buf_len) { + int len = buf_end_pos - buf_pos; + memmove(buf+buf_pos+1, buf+buf_pos, len+1); + buf_end_pos++; + return overwrite_char(ch); + } + } + return false; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::overwrite_char(char ch) { + + if(entry != gwinput::entry_noedit) { + + conditional(); + + switch(conversion) { + case gwinput::cvt_lowercase: + ch = (char)g_tolower(ch); + break; + case gwinput::cvt_uppercase: + ch = (char)g_toupper(ch); + break; + } + + buf[buf_pos] = ch; + if(buf_pos == buf_end_pos) { + buf_end_pos++; + buf[buf_end_pos] = NUL; + } + + if(conversion == gwinput::cvt_mixedcase) { + struplow(buf); + draw(); + } + else { + draw(pos); + } + + right(); + } + + return true; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::home() { + + adjust_mode(); + + pos = buf_pos = buf_left_pos = 0; + draw(); + move_cursor(); + return true; +} + + +// ------------------------------------------------------------------ + +bool gwinput::field::end() { + + adjust_mode(); + + buf_pos = buf_end_pos; + if(buf_pos == buf_len) + buf_pos--; + pos = minimum_of_two(max_pos, buf_pos); + buf_left_pos = buf_pos - pos; + draw(); + move_cursor(); + return true; +} + + +// ------------------------------------------------------------------ + +void gwinput::field::clear_field() { + + if(entry != gwinput::entry_noedit) { + + pos = buf_pos = buf_left_pos = buf_end_pos = 0; + *buf = NUL; + adjust_mode(); + draw(); + move_cursor(); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::field::clipboard_paste() { + + if(entry != gwinput::entry_noedit) { + + conditional(); + + gclipbrd clipbrd; + + if(not clipbrd.openread()) + return; + + char *clpbuf = (char *)throw_malloc(buf_len + 1); + + if(clipbrd.read(clpbuf, buf_len + 1)) { + + size_t len = strlen(clpbuf); + if((len != 0) and (clpbuf[len - 1] == '\n')) { + clpbuf[--len] = NUL; + + switch(conversion) { + case gwinput::cvt_lowercase: + strlwr(clpbuf); + break; + case gwinput::cvt_uppercase: + strupr(clpbuf); + break; + } + } + + if((buf_pos == buf_end_pos) or ((buf_pos + len) >= buf_len)) { + strxcat(buf, clpbuf, buf_len + 1); + buf_end_pos = strlen(buf); + end(); + } + else { + strxcat(clpbuf, buf + buf_pos, buf_len + 1); + buf[buf_pos] = NUL; + strxcat(buf, clpbuf, buf_len + 1); + buf_end_pos = strlen(buf); + for(int i = 0; i < len; i++) + move_right(); + } + + if(conversion == gwinput::cvt_mixedcase) { + struplow(buf); + draw(); + } + else { + draw(); + } + } + + throw_free(clpbuf); + + clipbrd.close(); + } +} + + +// ------------------------------------------------------------------ + +void gwinput::field::clipboard_copy() { + + if(entry != gwinput::entry_noedit) { + + gclipbrd clipbrd; + + clipbrd.writeclipbrd(buf); + } +} + + +// ------------------------------------------------------------------ + +bool gwinput2::run(int helpcat) { + + prepare_form(); + whelppcat(helpcat); + + while(handle_key(getxch())); + + whelpop(); + finish_form(); + + return not dropped; +} + + +// ------------------------------------------------------------------ +

[DLE] + Key_C_Q & 0xFF00u, // 0x1011 C [DC1] + Key_C_R & 0xFF00u, // 0x1312 C [DC2] + Key_C_S & 0xFF00u, // 0x1F13 C [DC3] + Key_C_T & 0xFF00u, // 0x1414 C [DC4] + Key_C_U & 0xFF00u, // 0x1615 C [NAK] + Key_C_V & 0xFF00u, // 0x2F16 C [SYN] + Key_C_W & 0xFF00u, // 0x1117 C [ETB] + Key_C_X & 0xFF00u, // 0x2D18 C [CAN] + Key_C_Y & 0xFF00u, // 0x1519 C [EM] + Key_C_Z & 0xFF00u, // 0x2C1A C [SUB] + Key_Esc & 0xFF00u, // 0x011B C <[ {> [ESC] (was: 0x1A1B) + Key_C_Bsl & 0xFF00u, // 0x2B1C C <\ |> [FS] + Key_C_Rbr & 0xFF00u, // 0x1B1D C <] }> [GS] + Key_C_6 & 0xFF00u, // 0x071E C <7 &> [RS] + Key_C_Min & 0xFF00u, // 0x0C1F C <- _> + Key_Space & 0xFF00u, // 0x3920 + Key_S_1 & 0xFF00u, // 0x0221 <1 !> + Key_S_Quo & 0xFF00u, // 0x2822 <' "> + Key_S_3 & 0xFF00u, // 0x0423 <3 #> + Key_S_4 & 0xFF00u, // 0x0524 <4 $> + Key_S_5 & 0xFF00u, // 0x0625 <5 %> + Key_S_7 & 0xFF00u, // 0x0826 <7 &> + Key_Quo & 0xFF00u, // 0x2827 <'> + Key_S_9 & 0xFF00u, // 0x0A28 <9 (> + Key_S_0 & 0xFF00u, // 0x0B29 <0 )> + Key_S_8 & 0xFF00u, // 0x092A <8 *> + Key_S_Equ & 0xFF00u, // 0x0D2B <= +> + Key_Com & 0xFF00u, // 0x332C <,> + Key_Min & 0xFF00u, // 0x0C2D <-> + Key_Dot & 0xFF00u, // 0x342E <.> + Key_Sls & 0xFF00u, // 0x352F + Key_0 & 0xFF00u, // 0x0B30 <0> + Key_1 & 0xFF00u, // 0x0231 <1> + Key_2 & 0xFF00u, // 0x0332 <2> + Key_3 & 0xFF00u, // 0x0433 <3> + Key_4 & 0xFF00u, // 0x0534 <4> + Key_5 & 0xFF00u, // 0x0635 <5> + Key_6 & 0xFF00u, // 0x0736 <6> + Key_7 & 0xFF00u, // 0x0837 <7> + Key_8 & 0xFF00u, // 0x0938 <8> + Key_9 & 0xFF00u, // 0x0A39 <9> + Key_S_Smi & 0xFF00u, // 0x273A <; :> + Key_Smi & 0xFF00u, // 0x273B <;> + Key_S_Com & 0xFF00u, // 0x333C <, >> + Key_Equ & 0xFF00u, // 0x0D3D <=> + Key_S_Dot & 0xFF00u, // 0x343E <. <> + Key_S_Sls & 0xFF00u, // 0x353F + Key_S_2 & 0xFF00u, // 0x0340 <2 @> + Key_S_A & 0xFF00u, // 0x1E41 + Key_S_B & 0xFF00u, // 0x3042 + Key_S_C & 0xFF00u, // 0x2E43 + Key_S_D & 0xFF00u, // 0x2044 + Key_S_E & 0xFF00u, // 0x1245 + Key_S_F & 0xFF00u, // 0x2146 + Key_S_G & 0xFF00u, // 0x2247 + Key_S_H & 0xFF00u, // 0x2348 + Key_S_I & 0xFF00u, // 0x1749 + Key_S_J & 0xFF00u, // 0x244A + Key_S_K & 0xFF00u, // 0x254B + Key_S_L & 0xFF00u, // 0x264C + Key_S_M & 0xFF00u, // 0x324D + Key_S_N & 0xFF00u, // 0x314E + Key_S_O & 0xFF00u, // 0x184F + Key_S_P & 0xFF00u, // 0x1950