1
0
mirror of synced 2026-01-22 18:20:53 +00:00
2020-09-09 15:11:45 -07:00

410 lines
13 KiB
C++

#ifndef __CURSES_WRAPPER_H__
#define __CURSES_WRAPPER_H__
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
#define NOMINMAX
#endif //NOMINMAX
#include <windows.h>
#undef MOUSE_MOVED
#else
#include <time.h>
#endif
#include <curses.h>
#include <panel.h>
#include <string>
#include <vector>
#include <exception>
#include "utils.h"
#include <vector>
#include <iostream>
namespace Curses {
struct Location_s {
Location_s(): X(0), Y(0) {}
explicit Location_s(int aX, int aY): X(aX), Y(aY) {}
int X;
int Y;
};
class Window_c : public std::ostream {
protected:
void Setup() {
NoDelay(true);
Keypad(true);
}
public:
explicit Window_c(WINDOW *aWnd) : std::ostream(&mStreamBuf), mWnd(aWnd), mOwner(false), mStreamBuf(*this), mIsScrollOk(false) {
Setup();
}
Window_c(WINDOW *aWnd, bool aOwner) : std::ostream(&mStreamBuf), mWnd(aWnd), mOwner(aOwner), mStreamBuf(*this), mIsScrollOk(false) {
Setup();
}
Window_c(const Window_c&) = delete;
Window_c(int aStartX, int aStartY, int aWidth, int aHeight) : std::ostream(&mStreamBuf), mStreamBuf(*this), mIsScrollOk(false) {
mWnd = newwin(aHeight, aWidth, aStartY, aStartX);
if (mWnd == nullptr) throw Generic_x("newwin failed");
mOwner = true;
Setup();
}
Window_c(const Window_c &aParent, int aOffsX, int aOffsY) : std::ostream(&mStreamBuf), mStreamBuf(*this), mIsScrollOk(false){
mWnd = newwin(aParent.GetMaxY() - 2 * aOffsY, aParent.GetMaxX() - 2 * aOffsX, aParent.GetBeginY() + aOffsY, aParent.GetBeginX() + aOffsX);
if (mWnd == nullptr) throw Generic_x("subwin failed");
mOwner = true;
Setup();
}
virtual ~Window_c() {
if (mOwner) delwin(mWnd);
}
void NoDelay(bool aNoDelay) {
nodelay(mWnd, aNoDelay);
}
void Keypad(bool aKeypad) {
keypad(mWnd, aKeypad);
}
virtual int GetMaxX() const { return getmaxx(mWnd); }
virtual int GetMaxY() const { return getmaxy(mWnd); }
virtual int GetBeginX() const { return getbegx(mWnd); }
virtual int GetBeginY() const { return getbegy(mWnd); }
Location_s GetMax() { return Location_s(GetMaxX(), GetMaxY()); }
void Move(int aX, int aY) {
if (wmove(mWnd,aY,aX) != OK) throw Generic_x("Move failed");
}
void Move(const Location_s &aLoc) { Move(aLoc.X, aLoc.Y); }
virtual void MoveWindow(int aStartX, int aStartY) {
if (mvwin(mWnd, aStartY, aStartX) != OK) throw Generic_x("mvwin failed");
}
void MoveWindow(const Location_s &aLoc) { MoveWindow(aLoc.X, aLoc.Y); }
virtual void Resize(int aWidth, int aHeight) {
if (wresize(mWnd, aHeight, aWidth) != OK) throw Generic_x("Resize failed");
Clear();
Move(0, 0);
}
void Resize(const Location_s &aLoc) { Resize(aLoc.X, aLoc.Y); }
void Grow(int aWidth, int aHeight) { Resize(GetMaxX() + aWidth, GetMaxY() + aHeight); }
void Grow(const Location_s &aLoc) { Resize(GetMaxX() + aLoc.X, GetMaxY() + aLoc.Y); }
void AddCh(chtype aCh) {
if (waddch(mWnd, aCh) != OK) throw Generic_x("AddCh failed");
}
chtype InCh() {
return winch(mWnd);
}
bool AddChNoThrow(chtype aCh) throw() {
return (waddch(mWnd, aCh) == OK);
}
void AddStr(const char *aCh) {
if (waddstr(mWnd, aCh) != OK) throw Generic_x("AddStr failed");
}
void AddStr(const std::string &aCh) { AddStr(aCh.c_str()); }
void AddStrN(const char *aCh, size_t aLen) {
if (waddnstr(mWnd, aCh, int(aLen)) != OK) throw Generic_x("AddStrN failed");
}
void MvAddStr(const char *aCh, int aX, int aY) {
if (mvwaddstr(mWnd, aY, aX, aCh) != OK) throw Generic_x("MvAddStr failed");
}
void MvAddStr(const std::string &aCh, int aX, int aY) { MvAddStr(aCh.c_str(), aX, aY); }
void MvAddStr(const char *aCh, const Location_s &aLoc) { MvAddStr(aCh, aLoc.X, aLoc.Y); }
void MvAddStr(const std::string &aCh, const Location_s &aLoc) { MvAddStr(aCh.c_str(), aLoc.X, aLoc.Y); }
void MvAddStrN(const char *aCh, size_t aLen, int aX, int aY) {
if (mvwaddnstr(mWnd, aY, aX, aCh, int(aLen)) != OK) throw Generic_x("MvAddStrN failed");
}
void MvAddStrN(const char *aCh, size_t aLen, const Location_s &aLoc) { MvAddStrN(aCh, aLen, aLoc.X, aLoc.Y); }
void AddStr(const char *aCh, int aX, int aY) {
Location_s CurLoc = GetCur();
MvAddStr(aCh, aX, aY);
Move(CurLoc);
}
void AddStr(const std::string &aCh, int aX, int aY) { AddStr(aCh.c_str(), aX, aY); }
void AddStr(const char *aCh, const Location_s &aLoc) { AddStr(aCh, aLoc.X, aLoc.Y); }
void AddStr(const std::string &aCh, const Location_s &aLoc) { AddStr(aCh.c_str(), aLoc.X, aLoc.Y); }
void AddStrN(const char *aCh, size_t aLen, int aX, int aY) {
Location_s CurLoc = GetCur();
MvAddStrN(aCh, aLen, aX, aY);
Move(CurLoc);
}
void AddStrN(const char *aCh, size_t aLen, const Location_s &aLoc) { AddStrN(aCh, aLen, aLoc.X, aLoc.Y); }
void ScrollOk(bool aScrollOk) {
if (scrollok(mWnd, aScrollOk) != OK) throw Generic_x("ScrollOk failed");
mIsScrollOk = aScrollOk;
}
bool IsScrollOk() const { return mIsScrollOk; }
int GetCurX() const { return getcurx(mWnd); }
int GetCurY() const { return getcury(mWnd); }
Location_s GetCur() const { return Location_s(GetCurX(),GetCurY()); }
void Clear() {
if (wclear(mWnd) != OK) throw Generic_x("Clear failed");
clear();
}
void ClearToBot() {
if (wclrtobot(mWnd) != OK) throw Generic_x("ClearToBot failed");
}
void ClearToEol() {
if (wclrtoeol(mWnd) != OK) throw Generic_x("ClearToEol failed");
}
virtual void Refresh() {
if (wrefresh(mWnd) != OK) throw Generic_x("Refresh failed");
}
void PushCur(int aX, int aY) {
PushCur(Location_s(aX, aY));
}
void PushCur(const Location_s &aLoc) {
mLocationStack.push_back(GetCur());
Move(aLoc);
}
void PopCur() {
if (mLocationStack.empty()) return;
Move(mLocationStack.back());
mLocationStack.pop_back();
}
bool IsKeyPressed(int &aCh) {
aCh = wgetch(mWnd);
if (aCh == ERR) {
return false;
}
return true;
}
void Scroll() {
if (scroll(mWnd) != OK)
throw Generic_x("Scroll failed");
}
void CopyRegion(const Location_s &aSrc, const Location_s &aDst, const Location_s &aSize, bool aOverlay) {
if (aSize.Y < 1) return;
Location_s LastCurPos = GetCur();
std::vector<chtype> Line((aSize.X+1)*(aSize.Y+1));
for (int Y=0;Y<aSize.Y;++Y) {
for(int X=0;X<aSize.X;++X) {
Move(Location_s(aSrc.X+X,aSrc.Y+Y));
Line[Y*aSize.X+X] = winch(mWnd);
}
}
for (int Y=0;Y<aSize.Y;++Y) {
Move(Location_s(aDst.X,aDst.Y+Y));
for(int X=0;X<aSize.X;++X) {
if (waddch(mWnd, Line[Y*aSize.X+X]) != OK) throw Generic_x("waddch failed");
}
}
Move(LastCurPos);
/* if (
copywin(mWnd, mWnd,
aSrc.Y, aSrc.X,
aDst.Y, aDst.X,
aDst.Y+aSize.Y, aDst.X+aSize.X,
aOverlay
) != OK
) {
stringstream Str;
Str << "CopyRegion failed with parameters:" << endl <<
" aSrc.Y=" << aSrc.Y << " aSrc.X=" << aSrc.X << endl <<
" aDst.Y=" << aDst.Y << " aDst.X=" << aDst.X << endl <<
" aSize.Y=" << aSize.Y << " aSize.X=" << aSize.X << endl <<
" aDst.Y+aSize.Y=" << aDst.Y+aSize.Y << " aDst.X+aSize.X=" << aDst.X+aSize.X << endl <<
" begy=" << getbegy(mWnd) << " begx=" << getbegx(mWnd) << endl <<
" maxy=" << getmaxy(mWnd) << " maxx=" << getmaxx(mWnd) << endl <<
" aOverlay=" << aOverlay;
throw Generic_x(Str.str());
}*/
}
virtual int GetCh() { return wgetch(mWnd); }
void Timeout(int aTimeout) { wtimeout(mWnd, aTimeout); }
void Box(chtype aVerticalCh = ACS_VLINE, chtype aHorizontalCh = ACS_HLINE) {
if (box(mWnd, aVerticalCh, aHorizontalCh)) throw Generic_x("Box failed");
}
void AttrSet(chtype aAttr) {
if (wattrset(mWnd, aAttr) != OK) throw Generic_x("AttrSet failed");
}
void AttrOn(chtype aAttr) {
if (wattron(mWnd, aAttr) != OK) throw Generic_x("AttrOn failed");
}
void AttrOff(chtype aAttr) {
if (wattroff(mWnd, aAttr) != OK) throw Generic_x("AttrOff failed");
}
void BkgdSet(chtype aAttr) {
wbkgdset(mWnd, aAttr);
}
/* Window_c &operator << (basic_ostream<char, char_traits<char> >& (*aFormatterFn)(basic_ostream<char, char_traits<char> >&)) {
stringstream StrStrm;
aFormatterFn(StrStrm);
AddStr(StrStrm.str());
if (StrStrm.str() == "\n") {
Refresh();
}
return *this;
}
template <typename tElement> Window_c &operator << (const tElement &aElement) {
stringstream StrStrm;
StrStrm << aElement;
AddStr(StrStrm.str());
return *this;
};*/
friend class SubWindow_c;
friend class Panel_c;
protected:
// A small streambuf derivative to support ostream-type interfaces
class StreamBuf_c : public std::streambuf
{
public:
explicit StreamBuf_c(Window_c &aParent) : mParent(aParent) {}
virtual int overflow(int aChar = EOF) override {
if (!mParent.AddChNoThrow(aChar)) return EOF;
return aChar;
}
virtual std::streamsize xsputn(const char *aStr, std::streamsize aCount) override {
try {
mParent.AddStrN(aStr, static_cast<size_t>(aCount));
}
catch (Generic_x &) {
return 0;
}
return aCount;
}
virtual int sync() override {
try {
mParent.Refresh();
}
catch (Generic_x &) {
return -1;
}
return 0;
}
protected:
Window_c &mParent;
};
WINDOW *mWnd;
bool mOwner;
StreamBuf_c mStreamBuf;
bool mIsScrollOk;
std::vector<Location_s> mLocationStack;
};
class Session_c: public Window_c {
public:
explicit Session_c(bool aDoInit = true): Window_c(initscr(), false), mInitialized(false) {
if (aDoInit) Open();
}
~Session_c() {
Close();
}
void Open() {
if (!mInitialized) {
cbreak();
noecho();
nodelay(mWnd,true);
scrollok(mWnd,true);
keypad(mWnd, true);
mOriginalSize = Location_s(getmaxx(mWnd), getmaxy(mWnd));
}
mInitialized = true;
}
void Close() {
if (mInitialized) {
ResizeTerm(mOriginalSize);
// if (isendwin()) {
clear();
refresh();
endwin();
// }
}
mInitialized = false;
}
Session_c(const Session_c&) = delete;
void ResizeTerm() { ResizeTerm(0, 0); }
void ResizeTerm(size_t aX, size_t aY) {
if (resize_term(int(aY), int(aX)) != OK) throw Generic_x("Terminal resize failed");
}
void ResizeTerm(const Location_s &aLoc) { ResizeTerm(aLoc.X, aLoc.Y); }
void Echo() { echo(); }
void NoEcho() { noecho(); }
void NoDelay(bool aDelay) { nodelay(mWnd,aDelay); }
protected:
Location_s mOriginalSize;
bool mInitialized;
};
class SubWindow_c : public Window_c {
public:
SubWindow_c(Window_c &aParent, int aOffsX, int aOffsY) : Window_c(nullptr, true), mParent(aParent) {
mWnd = subwin(mParent.mWnd, mParent.GetMaxY() - 2*aOffsY, mParent.GetMaxX() - 2*aOffsX, mParent.GetBeginY() + aOffsY, mParent.GetBeginX() + aOffsX);
if (mWnd == nullptr) throw Generic_x("subwin failed");
}
SubWindow_c(Window_c &aParent, int aBeginX, int aBeginY, int aWidth, int aHeight) : Window_c(nullptr, true), mParent(aParent) {
mWnd = subwin(mParent.mWnd, aHeight, aWidth, aBeginY, aBeginX);
if (mWnd == nullptr) throw Generic_x("subwin failed");
}
SubWindow_c(const SubWindow_c&) = delete;
virtual void Refresh() override {
touchwin(mParent.mWnd);
mParent.Refresh();
}
protected:
Window_c &mParent;
};
class Panel_c: public Window_c {
public:
Panel_c(Session_c &aSession) : Window_c(aSession.mWnd, false) {
mPanel = new_panel(mWnd);
if (mPanel == nullptr) throw Generic_x("new_panel failed");
set_panel_userptr(mPanel, this);
}
Panel_c(int aStartX, int aStartY, int aWidth, int aHeight): Window_c(aStartX, aStartY, aWidth, aHeight) {
mPanel = new_panel(mWnd);
if (mPanel == nullptr) throw Generic_x("new_panel failed");
set_panel_userptr(mPanel, this);
}
Panel_c(const Window_c &aParent, int aOffsX, int aOffsY): Window_c(aParent, aOffsX, aOffsY) {
mPanel = new_panel(mWnd);
if (mPanel == nullptr) throw Generic_x("new_panel failed");
set_panel_userptr(mPanel, this);
}
Panel_c(const Panel_c&) = delete;
virtual ~Panel_c() {
del_panel(mPanel);
}
void Bottom() {
if (bottom_panel(mPanel) != OK) throw Generic_x("Bottom failed");
}
void Top() {
if (top_panel(mPanel) != OK) throw Generic_x("Bottom failed");
}
void Hide() {
if (hide_panel(mPanel) != OK) throw Generic_x("Hide failed");
}
void Show() {
if (show_panel(mPanel) != OK) throw Generic_x("Show failed");
}
virtual void MoveWindow(int aStartX, int aStartY) {
if (move_panel(mPanel, aStartY, aStartX) != OK) throw Generic_x("MoveWindow failed on panel");
}
const Panel_c *Above() const {
PANEL *PanelAbove = panel_above(mPanel);
if (PanelAbove == nullptr) throw Generic_x("Above failed");
const Panel_c *RetVal = reinterpret_cast<const Panel_c*>(panel_userptr(PanelAbove));
if (RetVal == nullptr) throw Generic_x("Above is not a Panel_c");
return RetVal;
}
const Panel_c *Below() const {
PANEL *PanelBelow = panel_below(mPanel);
if (PanelBelow == nullptr) throw Generic_x("Above failed");
const Panel_c *RetVal = reinterpret_cast<const Panel_c*>(panel_userptr(PanelBelow));
if (RetVal == nullptr) throw Generic_x("Above is not a Panel_c");
return RetVal;
}
bool IsHidden() { return panel_hidden(mPanel) == OK; }
static void Update() {
update_panels();
doupdate();
}
virtual void Refresh() {
Update();
}
protected:
PANEL *mPanel;
};
};
#endif // __CURSES_WRAPPER_H__