/*************************************************************************** * 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 #include #include #include #include #include #include #include #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 PromptAborted(ArgT &&prompt) : m_prompt(std::forward(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 m_impl; }; std::istream &operator>>(std::istream &is, Color &f); typedef boost::optional 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 PromptHook; /// Sets helper to a specific value for the current scope struct ScopedPromptHook { template ScopedPromptHook(Window &w, HelperT &&helper) noexcept : m_w(w), m_hook(std::move(w.m_prompt_hook)) { m_w.m_prompt_hook = std::forward(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 void setPromptHook(HookT &&hook) { m_prompt_hook = std::forward(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 &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 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 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 > 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