540 lines
16 KiB
C++
540 lines
16 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2008-2014 by Andrzej Rybczak *
|
|
* electricityispower@gmail.com *
|
|
* *
|
|
* 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., *
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
***************************************************************************/
|
|
|
|
#ifndef NCMPCPP_WINDOW_H
|
|
#define NCMPCPP_WINDOW_H
|
|
|
|
#include "config.h"
|
|
|
|
#include "curses.h"
|
|
#include "gcc.h"
|
|
|
|
#include <boost/optional.hpp>
|
|
#include <functional>
|
|
#include <list>
|
|
#include <stack>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <queue>
|
|
|
|
#if NCURSES_MOUSE_VERSION == 1
|
|
# define BUTTON5_PRESSED (1U << 27)
|
|
#endif // NCURSES_MOUSE_VERSION == 1
|
|
|
|
// undefine macros with colliding names
|
|
#undef border
|
|
#undef scroll
|
|
|
|
/// NC namespace provides set of easy-to-use
|
|
/// wrappers over original curses library.
|
|
namespace NC {
|
|
|
|
namespace Key {
|
|
|
|
typedef uint32_t Type;
|
|
|
|
const Type None = -1;
|
|
|
|
// modifier masks
|
|
const Type Special = 1 << 31;
|
|
const Type Alt = 1 << 30;
|
|
const Type Ctrl = 1 << 29;
|
|
const Type Shift = 1 << 28;
|
|
|
|
// useful names
|
|
const Type Null = 0;
|
|
const Type Space = 32;
|
|
const Type Backspace = 127;
|
|
|
|
// ctrl-?
|
|
const Type Ctrl_A = 1;
|
|
const Type Ctrl_B = 2;
|
|
const Type Ctrl_C = 3;
|
|
const Type Ctrl_D = 4;
|
|
const Type Ctrl_E = 5;
|
|
const Type Ctrl_F = 6;
|
|
const Type Ctrl_G = 7;
|
|
const Type Ctrl_H = 8;
|
|
const Type Ctrl_I = 9;
|
|
const Type Ctrl_J = 10;
|
|
const Type Ctrl_K = 11;
|
|
const Type Ctrl_L = 12;
|
|
const Type Ctrl_M = 13;
|
|
const Type Ctrl_N = 14;
|
|
const Type Ctrl_O = 15;
|
|
const Type Ctrl_P = 16;
|
|
const Type Ctrl_Q = 17;
|
|
const Type Ctrl_R = 18;
|
|
const Type Ctrl_S = 19;
|
|
const Type Ctrl_T = 20;
|
|
const Type Ctrl_U = 21;
|
|
const Type Ctrl_V = 22;
|
|
const Type Ctrl_W = 23;
|
|
const Type Ctrl_X = 24;
|
|
const Type Ctrl_Y = 25;
|
|
const Type Ctrl_Z = 26;
|
|
const Type Ctrl_LeftBracket = 27;
|
|
const Type Ctrl_Backslash = 28;
|
|
const Type Ctrl_RightBracket = 29;
|
|
const Type Ctrl_Caret = 30;
|
|
const Type Ctrl_Underscore = 31;
|
|
|
|
// useful duplicates
|
|
const Type Tab = 9;
|
|
const Type Enter = 13;
|
|
const Type Escape = 27;
|
|
|
|
// special values, beyond one byte
|
|
const Type Insert = Special | 256;
|
|
const Type Delete = Special | 257;
|
|
const Type Home = Special | 258;
|
|
const Type End = Special | 259;
|
|
const Type PageUp = Special | 260;
|
|
const Type PageDown = Special | 261;
|
|
const Type Up = Special | 262;
|
|
const Type Down = Special | 263;
|
|
const Type Left = Special | 264;
|
|
const Type Right = Special | 265;
|
|
const Type F1 = Special | 266;
|
|
const Type F2 = Special | 267;
|
|
const Type F3 = Special | 268;
|
|
const Type F4 = Special | 269;
|
|
const Type F5 = Special | 270;
|
|
const Type F6 = Special | 271;
|
|
const Type F7 = Special | 272;
|
|
const Type F8 = Special | 273;
|
|
const Type F9 = Special | 274;
|
|
const Type F10 = Special | 275;
|
|
const Type F11 = Special | 276;
|
|
const Type F12 = Special | 277;
|
|
const Type Mouse = Special | 278;
|
|
|
|
}
|
|
|
|
/// Thrown if Ctrl-C or Ctrl-G is pressed during the call to Window::getString()
|
|
/// @see Window::getString()
|
|
struct PromptAborted : std::exception
|
|
{
|
|
template <typename ArgT>
|
|
PromptAborted(ArgT &&prompt)
|
|
: m_prompt(std::forward<ArgT>(prompt)) { }
|
|
|
|
virtual const char *what() const noexcept OVERRIDE { return m_prompt.c_str(); }
|
|
|
|
private:
|
|
std::string m_prompt;
|
|
};
|
|
|
|
struct Color
|
|
{
|
|
friend struct Window;
|
|
|
|
static const short transparent;
|
|
static const short previous;
|
|
|
|
Color() : m_impl(0, transparent, true, false) { }
|
|
Color(short foreground_value, short background_value,
|
|
bool is_default = false, bool is_end = false)
|
|
: m_impl(foreground_value, background_value, is_default, is_end)
|
|
{
|
|
if (isDefault() && isEnd())
|
|
throw std::logic_error("Color flag can't be marked as both 'default' and 'end'");
|
|
}
|
|
|
|
bool operator==(const Color &rhs) const { return m_impl == rhs.m_impl; }
|
|
bool operator!=(const Color &rhs) const { return m_impl != rhs.m_impl; }
|
|
bool operator<(const Color &rhs) const { return m_impl < rhs.m_impl; }
|
|
|
|
bool isDefault() const { return std::get<2>(m_impl); }
|
|
bool isEnd() const { return std::get<3>(m_impl); }
|
|
|
|
int pairNumber() const;
|
|
|
|
static Color Default;
|
|
static Color Black;
|
|
static Color Red;
|
|
static Color Green;
|
|
static Color Yellow;
|
|
static Color Blue;
|
|
static Color Magenta;
|
|
static Color Cyan;
|
|
static Color White;
|
|
static Color End;
|
|
|
|
private:
|
|
short foreground() const { return std::get<0>(m_impl); }
|
|
short background() const { return std::get<1>(m_impl); }
|
|
bool previousBackground() const { return background() == previous; }
|
|
|
|
std::tuple<short, short, bool, bool> m_impl;
|
|
};
|
|
|
|
std::istream &operator>>(std::istream &is, Color &f);
|
|
|
|
typedef boost::optional<Color> Border;
|
|
|
|
/// Terminal manipulation functions
|
|
enum class TermManip { ClearToEOL };
|
|
|
|
/// Format flags used by NCurses
|
|
enum class Format {
|
|
None,
|
|
Bold, NoBold,
|
|
Underline, NoUnderline,
|
|
Reverse, NoReverse,
|
|
AltCharset, NoAltCharset
|
|
};
|
|
|
|
/// This indicates how much the window has to be scrolled
|
|
enum class Scroll { Up, Down, PageUp, PageDown, Home, End };
|
|
|
|
namespace Mouse {
|
|
|
|
void enable();
|
|
void disable();
|
|
|
|
}
|
|
|
|
/// Initializes curses screen and sets some additional attributes
|
|
/// @param enable_colors enables colors
|
|
void initScreen(bool enable_colors, bool enable_mouse);
|
|
|
|
/// Destroys the screen
|
|
void destroyScreen();
|
|
|
|
/// Struct used for going to given coordinates
|
|
/// @see Window::operator<<()
|
|
struct XY
|
|
{
|
|
XY(int xx, int yy) : x(xx), y(yy) { }
|
|
int x;
|
|
int y;
|
|
};
|
|
|
|
/// Main class of NCurses namespace, used as base for other specialized windows
|
|
struct Window
|
|
{
|
|
/// Helper function that is periodically invoked
|
|
// inside Window::getString() function
|
|
/// @see Window::getString()
|
|
typedef std::function<bool(const char *)> PromptHook;
|
|
|
|
/// Sets helper to a specific value for the current scope
|
|
struct ScopedPromptHook
|
|
{
|
|
template <typename HelperT>
|
|
ScopedPromptHook(Window &w, HelperT &&helper) noexcept
|
|
: m_w(w), m_hook(std::move(w.m_prompt_hook)) {
|
|
m_w.m_prompt_hook = std::forward<HelperT>(helper);
|
|
}
|
|
~ScopedPromptHook() noexcept {
|
|
m_w.m_prompt_hook = std::move(m_hook);
|
|
}
|
|
|
|
private:
|
|
Window &m_w;
|
|
PromptHook m_hook;
|
|
};
|
|
|
|
Window() : m_window(nullptr) { }
|
|
|
|
/// Constructs an empty window with given parameters
|
|
/// @param startx X position of left upper corner of constructed window
|
|
/// @param starty Y position of left upper corner of constructed window
|
|
/// @param width width of constructed window
|
|
/// @param height height of constructed window
|
|
/// @param title title of constructed window
|
|
/// @param color base color of constructed window
|
|
/// @param border border of constructed window
|
|
Window(size_t startx, size_t starty, size_t width, size_t height,
|
|
std::string title, Color color, Border border);
|
|
|
|
Window(const Window &rhs);
|
|
Window(Window &&rhs);
|
|
Window &operator=(Window w);
|
|
|
|
virtual ~Window();
|
|
|
|
/// Allows for direct access to internal WINDOW pointer in case there
|
|
/// is no wrapper for a function from curses library one may want to use
|
|
/// @return internal WINDOW pointer
|
|
WINDOW *raw() const { return m_window; }
|
|
|
|
/// @return window's width
|
|
size_t getWidth() const;
|
|
|
|
/// @return window's height
|
|
size_t getHeight() const;
|
|
|
|
/// @return X position of left upper window's corner
|
|
size_t getStartX() const;
|
|
|
|
/// @return Y position of left upper window's corner
|
|
size_t getStarty() const;
|
|
|
|
/// @return window's title
|
|
const std::string &getTitle() const;
|
|
|
|
/// @return current window's color
|
|
const Color &getColor() const;
|
|
|
|
/// @return current window's border
|
|
const Border &getBorder() const;
|
|
|
|
/// @return current window's timeout
|
|
int getTimeout() const;
|
|
|
|
/// @return current mouse event if readKey() returned KEY_MOUSE
|
|
const MEVENT &getMouseEvent();
|
|
|
|
/// Reads the string from standard input using readline library.
|
|
/// @param base base string that has to be edited
|
|
/// @param length max length of the string, unlimited by default
|
|
/// @param width width of area that entry field can take. if it's reached, string
|
|
/// will be scrolled. if value is 0, field will be from cursor position to the end
|
|
/// of current line wide.
|
|
/// @param encrypted if set to true, '*' characters will be displayed instead of
|
|
/// actual text.
|
|
/// @return edited string
|
|
///
|
|
/// @see setPromptHook()
|
|
/// @see SetTimeout()
|
|
std::string prompt(const std::string &base = "", size_t width = -1, bool encrypted = false);
|
|
|
|
/// Moves cursor to given coordinates
|
|
/// @param x given X position
|
|
/// @param y given Y position
|
|
void goToXY(int x, int y);
|
|
|
|
/// @return x window coordinate
|
|
int getX();
|
|
|
|
/// @return y windows coordinate
|
|
int getY();
|
|
|
|
/// Used to indicate whether given coordinates of main screen lies within
|
|
/// window area or not and if they do, transform them into in-window coords.
|
|
/// Otherwise function doesn't modify its arguments.
|
|
/// @param x X position of main screen to be checked
|
|
/// @param y Y position of main screen to be checked
|
|
/// @return true if it transformed variables, false otherwise
|
|
bool hasCoords(int &x, int &y);
|
|
|
|
/// Sets hook used in getString()
|
|
/// @param hook pointer to function that matches getStringHelper prototype
|
|
/// @see getString()
|
|
template <typename HookT>
|
|
void setPromptHook(HookT &&hook) {
|
|
m_prompt_hook = std::forward<HookT>(hook);
|
|
}
|
|
|
|
/// Run current GetString helper function (if defined).
|
|
/// @see getString()
|
|
/// @return true if helper was run, false otherwise
|
|
bool runPromptHook(const char *arg, bool *done) const;
|
|
|
|
/// Sets window's base color
|
|
/// @param fg foregound base color
|
|
/// @param bg background base color
|
|
void setBaseColor(Color c);
|
|
|
|
/// Sets window's border
|
|
/// @param border new window's border
|
|
void setBorder(Border border);
|
|
|
|
/// Sets window's timeout
|
|
/// @param timeout window's timeout
|
|
void setTimeout(int timeout);
|
|
|
|
/// Sets window's title
|
|
/// @param new_title new title for window
|
|
void setTitle(const std::string &new_title);
|
|
|
|
/// Refreshed whole window and its border
|
|
/// @see refresh()
|
|
void display();
|
|
|
|
/// Refreshes whole window, but not the border
|
|
/// @see display()
|
|
virtual void refresh();
|
|
|
|
/// Moves the window to new coordinates
|
|
/// @param new_x new X position of left upper corner of window
|
|
/// @param new_y new Y position of left upper corner of window
|
|
virtual void moveTo(size_t new_x, size_t new_y);
|
|
|
|
/// Resizes the window
|
|
/// @param new_width new window's width
|
|
/// @param new_height new window's height
|
|
virtual void resize(size_t new_width, size_t new_height);
|
|
|
|
/// Cleares the window
|
|
virtual void clear();
|
|
|
|
/// Adds given file descriptor to the list that will be polled in
|
|
/// readKey() along with stdin and callback that will be invoked
|
|
/// when there is data waiting for reading in it
|
|
/// @param fd file descriptor
|
|
/// @param callback callback
|
|
void addFDCallback(int fd, void (*callback)());
|
|
|
|
/// Clears list of file descriptors and their callbacks
|
|
void clearFDCallbacksList();
|
|
|
|
/// Checks if list of file descriptors is empty
|
|
/// @return true if list is empty, false otherwise
|
|
bool FDCallbacksListEmpty() const;
|
|
|
|
/// Reads key from standard input (or takes it from input queue)
|
|
/// and writes it into read_key variable
|
|
Key::Type readKey();
|
|
|
|
/// Push single character into input queue, so it can get consumed by ReadKey
|
|
void pushChar(const NC::Key::Type ch);
|
|
|
|
/// @return const reference to internal input queue
|
|
const std::queue<NC::Key::Type> &inputQueue() { return m_input_queue; }
|
|
|
|
/// Scrolls the window by amount of lines given in its parameter
|
|
/// @param where indicates how many lines it has to scroll
|
|
virtual void scroll(Scroll where);
|
|
|
|
Window &operator<<(TermManip tm);
|
|
Window &operator<<(const Color &color);
|
|
Window &operator<<(Format format);
|
|
Window &operator<<(const XY &coords);
|
|
Window &operator<<(const char *s);
|
|
Window &operator<<(char c);
|
|
Window &operator<<(const wchar_t *ws);
|
|
Window &operator<<(wchar_t wc);
|
|
Window &operator<<(int i);
|
|
Window &operator<<(double d);
|
|
Window &operator<<(size_t s);
|
|
Window &operator<<(const std::string &s);
|
|
Window &operator<<(const std::wstring &ws);
|
|
protected:
|
|
/// Sets colors of window (interal use only)
|
|
/// @param fg foregound color
|
|
/// @param bg background color
|
|
///
|
|
void setColor(Color c);
|
|
|
|
/// Refreshes window's border
|
|
///
|
|
void refreshBorder() const;
|
|
|
|
/// Changes dimensions of window, called from resize()
|
|
/// @param width new window's width
|
|
/// @param height new window's height
|
|
/// @see resize()
|
|
///
|
|
void adjustDimensions(size_t width, size_t height);
|
|
|
|
/// Deletes old window and creates new. It's called by resize(),
|
|
/// SetBorder() or setTitle() since internally windows are
|
|
/// handled as curses pads and change in size requires to delete
|
|
/// them and create again, there is no way to change size of pad.
|
|
/// @see SetBorder()
|
|
/// @see setTitle()
|
|
/// @see resize()
|
|
///
|
|
virtual void recreate(size_t width, size_t height);
|
|
|
|
/// internal WINDOW pointers
|
|
WINDOW *m_window;
|
|
|
|
/// start points and dimensions
|
|
size_t m_start_x;
|
|
size_t m_start_y;
|
|
size_t m_width;
|
|
size_t m_height;
|
|
|
|
/// window timeout
|
|
int m_window_timeout;
|
|
|
|
/// current colors
|
|
Color m_color;
|
|
|
|
/// base colors
|
|
Color m_base_color;
|
|
|
|
/// current border
|
|
Border m_border;
|
|
|
|
private:
|
|
Key::Type getInputChar(int key);
|
|
|
|
/// Sets state of bold attribute (internal use only)
|
|
/// @param bold_state state of bold attribute
|
|
///
|
|
void bold(bool bold_state) const;
|
|
|
|
/// Sets state of underline attribute (internal use only)
|
|
/// @param underline_state state of underline attribute
|
|
///
|
|
void underline(bool underline_state) const;
|
|
|
|
/// Sets state of reverse attribute (internal use only)
|
|
/// @param reverse_state state of reverse attribute
|
|
///
|
|
void reverse(bool reverse_state) const;
|
|
|
|
/// Sets state of altcharset attribute (internal use only)
|
|
/// @param altcharset_state state of altcharset attribute
|
|
///
|
|
void altCharset(bool altcharset_state) const;
|
|
|
|
/// pointer to helper function used by getString()
|
|
/// @see getString()
|
|
///
|
|
PromptHook m_prompt_hook;
|
|
|
|
/// window title
|
|
std::string m_title;
|
|
|
|
/// stack of colors
|
|
std::stack<Color> m_color_stack;
|
|
|
|
/// input queue of a window. you can put characters there using
|
|
/// PushChar and they will be immediately consumed and
|
|
/// returned by ReadKey
|
|
std::queue<Key::Type> m_input_queue;
|
|
|
|
/// containter used for additional file descriptors that have
|
|
/// to be polled in ReadKey() and correspondent callbacks that
|
|
/// are invoked if there is data available in them
|
|
typedef std::vector< std::pair<int, void (*)()> > FDCallbacks;
|
|
FDCallbacks m_fds;
|
|
|
|
MEVENT m_mouse_event;
|
|
bool m_escape_terminal_sequences;
|
|
|
|
/// counters for format flags
|
|
int m_bold_counter;
|
|
int m_underline_counter;
|
|
int m_reverse_counter;
|
|
int m_alt_charset_counter;
|
|
};
|
|
|
|
}
|
|
|
|
#endif // NCMPCPP_WINDOW_H
|