Move ncurses related files to curses directory

This commit is contained in:
Andrzej Rybczak
2016-12-22 15:25:25 +01:00
parent 44d343d5a2
commit 478f4454d8
36 changed files with 39 additions and 38 deletions

524
src/curses/menu.h Normal file
View File

@@ -0,0 +1,524 @@
/***************************************************************************
* Copyright (C) 2008-2016 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_MENU_H
#define NCMPCPP_MENU_H
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/detail/any_iterator.hpp>
#include <cassert>
#include <functional>
#include <iterator>
#include <memory>
#include <set>
#include "utility/const.h"
#include "strbuffer.h"
#include "window.h"
namespace NC {
struct List
{
struct Properties
{
enum Type {
None = 0,
Bold = (1 << 0),
Selectable = (1 << 1),
Selected = (1 << 2),
Inactive = (1 << 3),
Separator = (1 << 4)
};
Properties(Type properties = Selectable)
: m_properties(properties)
{ }
void setBold(bool is_bold)
{
if (is_bold)
m_properties |= Bold;
else
m_properties &= ~Bold;
}
void setSelectable(bool is_selectable)
{
if (is_selectable)
m_properties |= Selectable;
else
m_properties &= ~(Selectable | Selected);
}
void setSelected(bool is_selected)
{
if (!isSelectable())
return;
if (is_selected)
m_properties |= Selected;
else
m_properties &= ~Selected;
}
void setInactive(bool is_inactive)
{
if (is_inactive)
m_properties |= Inactive;
else
m_properties &= ~Inactive;
}
void setSeparator(bool is_separator)
{
if (is_separator)
m_properties |= Separator;
else
m_properties &= ~Separator;
}
bool isBold() const { return m_properties & Bold; }
bool isSelectable() const { return m_properties & Selectable; }
bool isSelected() const { return m_properties & Selected; }
bool isInactive() const { return m_properties & Inactive; }
bool isSeparator() const { return m_properties & Separator; }
private:
unsigned m_properties;
};
template <typename ValueT>
using PropertiesIterator = boost::range_detail::any_iterator<
ValueT,
boost::random_access_traversal_tag,
ValueT &,
std::ptrdiff_t
>;
typedef PropertiesIterator<Properties> Iterator;
typedef PropertiesIterator<const Properties> ConstIterator;
virtual ~List() { }
virtual bool empty() const = 0;
virtual size_t size() const = 0;
virtual size_t choice() const = 0;
virtual void highlight(size_t pos) = 0;
virtual Iterator currentP() = 0;
virtual ConstIterator currentP() const = 0;
virtual Iterator beginP() = 0;
virtual ConstIterator beginP() const = 0;
virtual Iterator endP() = 0;
virtual ConstIterator endP() const = 0;
};
inline List::Properties::Type operator|(List::Properties::Type lhs, List::Properties::Type rhs)
{
return List::Properties::Type(unsigned(lhs) | unsigned(rhs));
}
inline List::Properties::Type &operator|=(List::Properties::Type &lhs, List::Properties::Type rhs)
{
lhs = lhs | rhs;
return lhs;
}
inline List::Properties::Type operator&(List::Properties::Type lhs, List::Properties::Type rhs)
{
return List::Properties::Type(unsigned(lhs) & unsigned(rhs));
}
inline List::Properties::Type &operator&=(List::Properties::Type &lhs, List::Properties::Type rhs)
{
lhs = lhs & rhs;
return lhs;
}
// for range-based for loop
inline List::Iterator begin(List &list) { return list.beginP(); }
inline List::ConstIterator begin(const List &list) { return list.beginP(); }
inline List::Iterator end(List &list) { return list.endP(); }
inline List::ConstIterator end(const List &list) { return list.endP(); }
/// Generic menu capable of holding any std::vector compatible values.
template <typename ItemT>
struct Menu: Window, List
{
struct Item
{
friend struct Menu<ItemT>;
typedef ItemT Type;
Item()
: m_impl(std::make_shared<std::tuple<ItemT, Properties>>())
{ }
template <typename ValueT, typename PropertiesT>
Item(ValueT &&value_, PropertiesT properties_)
: m_impl(
std::make_shared<std::tuple<ItemT, List::Properties>>(
std::forward<ValueT>(value_),
std::forward<PropertiesT>(properties_)))
{ }
ItemT &value() { return std::get<0>(*m_impl); }
const ItemT &value() const { return std::get<0>(*m_impl); }
Properties &properties() { return std::get<1>(*m_impl); }
const Properties &properties() const { return std::get<1>(*m_impl); }
// Forward methods to List::Properties.
void setBold (bool is_bold) { properties().setBold(is_bold); }
void setSelectable(bool is_selectable) { properties().setSelectable(is_selectable); }
void setSelected (bool is_selected) { properties().setSelected(is_selected); }
void setInactive (bool is_inactive) { properties().setInactive(is_inactive); }
void setSeparator (bool is_separator) { properties().setSeparator(is_separator); }
bool isBold() const { return properties().isBold(); }
bool isSelectable() const { return properties().isSelectable(); }
bool isSelected() const { return properties().isSelected(); }
bool isInactive() const { return properties().isInactive(); }
bool isSeparator() const { return properties().isSeparator(); }
// Make a deep copy of Item.
Item copy() const {
return Item(value(), properties());
}
private:
template <Const const_>
struct ExtractProperties
{
typedef ExtractProperties type;
typedef typename std::conditional<
const_ == Const::Yes,
const Properties,
Properties>::type Properties_;
typedef typename std::conditional<
const_ == Const::Yes,
const Item,
Item>::type Item_;
Properties_ &operator()(Item_ &i) const {
return i.properties();
}
};
template <Const const_>
struct ExtractValue
{
typedef ExtractValue type;
typedef typename std::conditional<
const_ == Const::Yes,
const ItemT,
ItemT>::type Value_;
typedef typename std::conditional<
const_ == Const::Yes,
const Item,
Item>::type Item_;
Value_ &operator()(Item_ &i) const {
return i.value();
}
};
static Item mkSeparator()
{
Item item;
item.setSelectable(false);
item.setSeparator(true);
return item;
}
std::shared_ptr<std::tuple<ItemT, Properties>> m_impl;
};
typedef typename std::vector<Item>::iterator Iterator;
typedef typename std::vector<Item>::const_iterator ConstIterator;
typedef std::reverse_iterator<Iterator> ReverseIterator;
typedef std::reverse_iterator<ConstIterator> ConstReverseIterator;
typedef boost::transform_iterator<
typename Item::template ExtractValue<Const::No>,
Iterator> ValueIterator;
typedef boost::transform_iterator<
typename Item::template ExtractValue<Const::Yes>,
ConstIterator> ConstValueIterator;
typedef std::reverse_iterator<ValueIterator> ReverseValueIterator;
typedef std::reverse_iterator<ConstValueIterator> ConstReverseValueIterator;
typedef boost::transform_iterator<
typename Item::template ExtractProperties<Const::No>,
Iterator> PropertiesIterator;
typedef boost::transform_iterator<
typename Item::template ExtractProperties<Const::Yes>,
ConstIterator> ConstPropertiesIterator;
// For compliance with boost utilities.
typedef Iterator iterator;
typedef ConstIterator const_iterator;
/// Function helper prototype used to display each option on the screen.
/// If not set by setItemDisplayer(), menu won't display anything.
/// @see setItemDisplayer()
typedef std::function<void(Menu<ItemT> &)> ItemDisplayer;
typedef std::function<bool(const Item &)> FilterPredicate;
Menu();
Menu(size_t startx, size_t starty, size_t width, size_t height,
const std::string &title, Color color, Border border);
Menu(const Menu &rhs);
Menu(Menu &&rhs);
Menu &operator=(Menu rhs);
/// Sets helper function that is responsible for displaying items
/// @param ptr function pointer that matches the ItemDisplayer prototype
template <typename ItemDisplayerT>
void setItemDisplayer(ItemDisplayerT &&displayer);
/// Resizes the list to given size (adequate to std::vector::resize())
/// @param size requested size
void resizeList(size_t new_size);
/// Adds a new option to list
void addItem(ItemT item, Properties::Type properties = Properties::Selectable);
/// Adds separator to list
void addSeparator();
/// Inserts a new option to the list at given position
void insertItem(size_t pos, ItemT item, Properties::Type properties = Properties::Selectable);
/// Inserts separator to list at given position
/// @param pos initial position of inserted separator
void insertSeparator(size_t pos);
/// Moves the highlighted position to the given line of window
/// @param y Y position of menu window to be highlighted
/// @return true if the position is reachable, false otherwise
bool Goto(size_t y);
/// Checks if list is empty
/// @return true if list is empty, false otherwise
virtual bool empty() const override { return m_items->empty(); }
/// @return size of the list
virtual size_t size() const override { return m_items->size(); }
/// @return currently highlighted position
virtual size_t choice() const override;
/// Highlights given position
/// @param pos position to be highlighted
virtual void highlight(size_t position) override;
/// Refreshes the menu window
/// @see Window::refresh()
virtual void refresh() override;
/// Scrolls by given amount of lines
/// @param where indicated where exactly one wants to go
/// @see Window::scroll()
virtual void scroll(Scroll where) override;
/// Cleares all options, used filters etc. It doesn't reset highlighted position though.
/// @see reset()
virtual void clear() override;
/// Sets highlighted position to 0
void reset();
/// Apply filter predicate to items in the menu and show the ones for which it
/// returned true.
template <typename PredicateT>
void applyFilter(PredicateT &&pred);
/// Reapply previously applied filter.
void reapplyFilter();
/// Get current filter predicate.
template <typename TargetT>
const TargetT *filterPredicate() const;
/// Clear results of applyFilter and show all items.
void clearFilter();
/// @return true if menu is filtered.
bool isFiltered() const { return m_items == &m_filtered_items; }
/// Show all items.
void showAllItems() { m_items = &m_all_items; }
/// Show filtered items.
void showFilteredItems() { m_items = &m_filtered_items; }
/// Sets prefix, that is put before each selected item to indicate its selection
/// Note that the passed variable is not deleted along with menu object.
/// @param b pointer to buffer that contains the prefix
void setSelectedPrefix(const Buffer &b) { m_selected_prefix = b; }
/// Sets suffix, that is put after each selected item to indicate its selection
/// Note that the passed variable is not deleted along with menu object.
/// @param b pointer to buffer that contains the suffix
void setSelectedSuffix(const Buffer &b) { m_selected_suffix = b; }
/// Sets custom color of highlighted position
/// @param col custom color
void setHighlightColor(Color color) { m_highlight_color = std::move(color); }
/// @return state of highlighting
bool isHighlighted() { return m_highlight_enabled; }
/// Turns on/off highlighting
/// @param state state of hihglighting
void setHighlighting(bool state) { m_highlight_enabled = state; }
/// Turns on/off cyclic scrolling
/// @param state state of cyclic scrolling
void cyclicScrolling(bool state) { m_cyclic_scroll_enabled = state; }
/// Turns on/off centered cursor
/// @param state state of centered cursor
void centeredCursor(bool state) { m_autocenter_cursor = state; }
/// @return currently drawn item. The result is defined only within
/// drawing function that is called by refresh()
/// @see refresh()
ConstIterator drawn() const { return begin() + m_drawn_position; }
/// @param pos requested position
/// @return reference to item at given position
/// @throw std::out_of_range if given position is out of range
Menu<ItemT>::Item &at(size_t pos) { return m_items->at(pos); }
/// @param pos requested position
/// @return const reference to item at given position
/// @throw std::out_of_range if given position is out of range
const Menu<ItemT>::Item &at(size_t pos) const { return m_items->at(pos); }
/// @param pos requested position
/// @return const reference to item at given position
const Menu<ItemT>::Item &operator[](size_t pos) const { return (*m_items)[pos]; }
/// @param pos requested position
/// @return const reference to item at given position
Menu<ItemT>::Item &operator[](size_t pos) { return (*m_items)[pos]; }
Iterator current() { return Iterator(m_items->begin() + m_highlight); }
ConstIterator current() const { return ConstIterator(m_items->begin() + m_highlight); }
ReverseIterator rcurrent() {
if (empty())
return rend();
else
return ReverseIterator(++current());
}
ConstReverseIterator rcurrent() const {
if (empty())
return rend();
else
return ConstReverseIterator(++current());
}
ValueIterator currentV() { return ValueIterator(m_items->begin() + m_highlight); }
ConstValueIterator currentV() const { return ConstValueIterator(m_items->begin() + m_highlight); }
ReverseValueIterator rcurrentV() {
if (empty())
return rendV();
else
return ReverseValueIterator(++currentV());
}
ConstReverseValueIterator rcurrentV() const {
if (empty())
return rendV();
else
return ConstReverseValueIterator(++currentV());
}
Iterator begin() { return Iterator(m_items->begin()); }
ConstIterator begin() const { return ConstIterator(m_items->begin()); }
Iterator end() { return Iterator(m_items->end()); }
ConstIterator end() const { return ConstIterator(m_items->end()); }
ReverseIterator rbegin() { return ReverseIterator(end()); }
ConstReverseIterator rbegin() const { return ConstReverseIterator(end()); }
ReverseIterator rend() { return ReverseIterator(begin()); }
ConstReverseIterator rend() const { return ConstReverseIterator(begin()); }
ValueIterator beginV() { return ValueIterator(begin()); }
ConstValueIterator beginV() const { return ConstValueIterator(begin()); }
ValueIterator endV() { return ValueIterator(end()); }
ConstValueIterator endV() const { return ConstValueIterator(end()); }
ReverseValueIterator rbeginV() { return ReverseValueIterator(endV()); }
ConstReverseIterator rbeginV() const { return ConstReverseValueIterator(endV()); }
ReverseValueIterator rendV() { return ReverseValueIterator(beginV()); }
ConstReverseValueIterator rendV() const { return ConstReverseValueIterator(beginV()); }
virtual List::Iterator currentP() override {
return List::Iterator(PropertiesIterator(m_items->begin() + m_highlight));
}
virtual List::ConstIterator currentP() const override {
return List::ConstIterator(ConstPropertiesIterator(m_items->begin() + m_highlight));
}
virtual List::Iterator beginP() override {
return List::Iterator(PropertiesIterator(m_items->begin()));
}
virtual List::ConstIterator beginP() const override {
return List::ConstIterator(ConstPropertiesIterator(m_items->begin()));
}
virtual List::Iterator endP() override {
return List::Iterator(PropertiesIterator(m_items->end()));
}
virtual List::ConstIterator endP() const override {
return List::ConstIterator(ConstPropertiesIterator(m_items->end()));
}
private:
bool isHighlightable(size_t pos)
{
return !(*m_items)[pos].isSeparator()
&& !(*m_items)[pos].isInactive();
}
ItemDisplayer m_item_displayer;
FilterPredicate m_filter_predicate;
std::vector<Item> *m_items;
std::vector<Item> m_all_items;
std::vector<Item> m_filtered_items;
size_t m_beginning;
size_t m_highlight;
Color m_highlight_color;
bool m_highlight_enabled;
bool m_cyclic_scroll_enabled;
bool m_autocenter_cursor;
size_t m_drawn_position;
Buffer m_selected_prefix;
Buffer m_selected_suffix;
};
}
#endif // NCMPCPP_MENU_H

398
src/curses/menu_impl.h Normal file
View File

@@ -0,0 +1,398 @@
/***************************************************************************
* Copyright (C) 2008-2016 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_MENU_IMPL_H
#define NCMPCPP_MENU_IMPL_H
#include "menu.h"
namespace NC {
template <typename ItemT>
Menu<ItemT>::Menu()
{
m_items = &m_all_items;
}
template <typename ItemT>
Menu<ItemT>::Menu(size_t startx,
size_t starty,
size_t width,
size_t height,
const std::string &title,
Color color,
Border border)
: Window(startx, starty, width, height, title, std::move(color), border)
, m_item_displayer(nullptr)
, m_filter_predicate(nullptr)
, m_beginning(0)
, m_highlight(0)
, m_highlight_color(m_base_color)
, m_highlight_enabled(true)
, m_cyclic_scroll_enabled(false)
, m_autocenter_cursor(false)
{
m_items = &m_all_items;
}
template <typename ItemT>
Menu<ItemT>::Menu(const Menu &rhs)
: Window(rhs)
, m_item_displayer(rhs.m_item_displayer)
, m_filter_predicate(rhs.m_filter_predicate)
, m_beginning(rhs.m_beginning)
, m_highlight(rhs.m_highlight)
, m_highlight_color(rhs.m_highlight_color)
, m_highlight_enabled(rhs.m_highlight_enabled)
, m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
, m_autocenter_cursor(rhs.m_autocenter_cursor)
, m_drawn_position(rhs.m_drawn_position)
, m_selected_prefix(rhs.m_selected_prefix)
, m_selected_suffix(rhs.m_selected_suffix)
{
// TODO: move filtered items
m_all_items.reserve(rhs.m_all_items.size());
for (const auto &item : rhs.m_all_items)
m_all_items.push_back(item.copy());
m_items = &m_all_items;
}
template <typename ItemT>
Menu<ItemT>::Menu(Menu &&rhs)
: Window(rhs)
, m_item_displayer(std::move(rhs.m_item_displayer))
, m_filter_predicate(std::move(rhs.m_filter_predicate))
, m_all_items(std::move(rhs.m_all_items))
, m_filtered_items(std::move(rhs.m_filtered_items))
, m_beginning(rhs.m_beginning)
, m_highlight(rhs.m_highlight)
, m_highlight_color(rhs.m_highlight_color)
, m_highlight_enabled(rhs.m_highlight_enabled)
, m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
, m_autocenter_cursor(rhs.m_autocenter_cursor)
, m_drawn_position(rhs.m_drawn_position)
, m_selected_prefix(std::move(rhs.m_selected_prefix))
, m_selected_suffix(std::move(rhs.m_selected_suffix))
{
if (rhs.m_items == &rhs.m_all_items)
m_items = &m_all_items;
else
m_items = &m_filtered_items;
}
template <typename ItemT>
Menu<ItemT> &Menu<ItemT>::operator=(Menu rhs)
{
std::swap(static_cast<Window &>(*this), static_cast<Window &>(rhs));
std::swap(m_item_displayer, rhs.m_item_displayer);
std::swap(m_filter_predicate, rhs.m_filter_predicate);
std::swap(m_all_items, rhs.m_all_items);
std::swap(m_filtered_items, rhs.m_filtered_items);
std::swap(m_beginning, rhs.m_beginning);
std::swap(m_highlight, rhs.m_highlight);
std::swap(m_highlight_color, rhs.m_highlight_color);
std::swap(m_highlight_enabled, rhs.m_highlight_enabled);
std::swap(m_cyclic_scroll_enabled, rhs.m_cyclic_scroll_enabled);
std::swap(m_autocenter_cursor, rhs.m_autocenter_cursor);
std::swap(m_drawn_position, rhs.m_drawn_position);
std::swap(m_selected_prefix, rhs.m_selected_prefix);
std::swap(m_selected_suffix, rhs.m_selected_suffix);
if (rhs.m_items == &rhs.m_all_items)
m_items = &m_all_items;
else
m_items = &m_filtered_items;
return *this;
}
template <typename ItemT> template <typename ItemDisplayerT>
void Menu<ItemT>::setItemDisplayer(ItemDisplayerT &&displayer)
{
m_item_displayer = std::forward<ItemDisplayerT>(displayer);
}
template <typename ItemT>
void Menu<ItemT>::resizeList(size_t new_size)
{
m_all_items.resize(new_size);
}
template <typename ItemT>
void Menu<ItemT>::addItem(ItemT item, Properties::Type properties)
{
m_all_items.push_back(Item(std::move(item), properties));
}
template <typename ItemT>
void Menu<ItemT>::addSeparator()
{
m_all_items.push_back(Item::mkSeparator());
}
template <typename ItemT>
void Menu<ItemT>::insertItem(size_t pos, ItemT item, Properties::Type properties)
{
m_all_items.insert(m_all_items.begin()+pos, Item(std::move(item), properties));
}
template <typename ItemT>
void Menu<ItemT>::insertSeparator(size_t pos)
{
m_all_items.insert(m_all_items.begin()+pos, Item::mkSeparator());
}
template <typename ItemT>
bool Menu<ItemT>::Goto(size_t y)
{
if (!isHighlightable(m_beginning+y))
return false;
m_highlight = m_beginning+y;
return true;
}
template <typename ItemT>
void Menu<ItemT>::refresh()
{
if (m_items->empty())
{
Window::clear();
Window::refresh();
return;
}
size_t max_beginning = 0;
if (m_items->size() > m_height)
max_beginning = m_items->size() - m_height;
m_beginning = std::min(m_beginning, max_beginning);
// if highlighted position is off the screen, make it visible
m_highlight = std::min(m_highlight, m_beginning+m_height-1);
// if highlighted position is invalid, correct it
m_highlight = std::min(m_highlight, m_items->size()-1);
if (!isHighlightable(m_highlight))
{
scroll(Scroll::Up);
if (!isHighlightable(m_highlight))
scroll(Scroll::Down);
}
size_t line = 0;
const size_t end_ = m_beginning+m_height;
m_drawn_position = m_beginning;
for (; m_drawn_position < end_; ++m_drawn_position, ++line)
{
goToXY(0, line);
if (m_drawn_position >= m_items->size())
{
for (; line < m_height; ++line)
mvwhline(m_window, line, 0, NC::Key::Space, m_width);
break;
}
if ((*m_items)[m_drawn_position].isSeparator())
{
mvwhline(m_window, line, 0, 0, m_width);
continue;
}
if ((*m_items)[m_drawn_position].isBold())
*this << Format::Bold;
if (m_highlight_enabled && m_drawn_position == m_highlight)
{
*this << Format::Reverse;
*this << m_highlight_color;
}
mvwhline(m_window, line, 0, NC::Key::Space, m_width);
if ((*m_items)[m_drawn_position].isSelected())
*this << m_selected_prefix;
if (m_item_displayer)
m_item_displayer(*this);
if ((*m_items)[m_drawn_position].isSelected())
*this << m_selected_suffix;
if (m_highlight_enabled && m_drawn_position == m_highlight)
{
*this << Color::End;
*this << Format::NoReverse;
}
if ((*m_items)[m_drawn_position].isBold())
*this << Format::NoBold;
}
Window::refresh();
}
template <typename ItemT>
void Menu<ItemT>::scroll(Scroll where)
{
if (m_items->empty())
return;
size_t max_highlight = m_items->size()-1;
size_t max_beginning = m_items->size() < m_height ? 0 : m_items->size()-m_height;
size_t max_visible_highlight = m_beginning+m_height-1;
switch (where)
{
case Scroll::Up:
{
if (m_highlight <= m_beginning && m_highlight > 0)
--m_beginning;
if (m_highlight == 0)
{
if (m_cyclic_scroll_enabled)
return scroll(Scroll::End);
break;
}
else
--m_highlight;
if (!isHighlightable(m_highlight))
scroll(m_highlight == 0 && !m_cyclic_scroll_enabled ? Scroll::Down : Scroll::Up);
break;
}
case Scroll::Down:
{
if (m_highlight >= max_visible_highlight && m_highlight < max_highlight)
++m_beginning;
if (m_highlight == max_highlight)
{
if (m_cyclic_scroll_enabled)
return scroll(Scroll::Home);
break;
}
else
++m_highlight;
if (!isHighlightable(m_highlight))
scroll(m_highlight == max_highlight && !m_cyclic_scroll_enabled ? Scroll::Up : Scroll::Down);
break;
}
case Scroll::PageUp:
{
if (m_cyclic_scroll_enabled && m_highlight == 0)
return scroll(Scroll::End);
if (m_highlight < m_height)
m_highlight = 0;
else
m_highlight -= m_height;
if (m_beginning < m_height)
m_beginning = 0;
else
m_beginning -= m_height;
if (!isHighlightable(m_highlight))
scroll(m_highlight == 0 && !m_cyclic_scroll_enabled ? Scroll::Down : Scroll::Up);
break;
}
case Scroll::PageDown:
{
if (m_cyclic_scroll_enabled && m_highlight == max_highlight)
return scroll(Scroll::Home);
m_highlight += m_height;
m_beginning += m_height;
m_beginning = std::min(m_beginning, max_beginning);
m_highlight = std::min(m_highlight, max_highlight);
if (!isHighlightable(m_highlight))
scroll(m_highlight == max_highlight && !m_cyclic_scroll_enabled ? Scroll::Up : Scroll::Down);
break;
}
case Scroll::Home:
{
m_highlight = 0;
m_beginning = 0;
if (!isHighlightable(m_highlight))
scroll(Scroll::Down);
break;
}
case Scroll::End:
{
m_highlight = max_highlight;
m_beginning = max_beginning;
if (!isHighlightable(m_highlight))
scroll(Scroll::Up);
break;
}
}
if (m_autocenter_cursor)
highlight(m_highlight);
}
template <typename ItemT>
void Menu<ItemT>::reset()
{
m_highlight = 0;
m_beginning = 0;
}
template <typename ItemT>
void Menu<ItemT>::clear()
{
// Don't clear filter related stuff here.
m_all_items.clear();
m_filtered_items.clear();
}
template <typename ItemT>
void Menu<ItemT>::highlight(size_t pos)
{
assert(pos < m_items->size());
m_highlight = pos;
size_t half_height = m_height/2;
if (pos < half_height)
m_beginning = 0;
else
m_beginning = pos-half_height;
}
template <typename ItemT>
size_t Menu<ItemT>::choice() const
{
assert(!empty());
return m_highlight;
}
template <typename ItemT> template <typename PredicateT>
void Menu<ItemT>::applyFilter(PredicateT &&pred)
{
m_filter_predicate = std::forward<PredicateT>(pred);
m_filtered_items.clear();
for (const auto &item : m_all_items)
if (m_filter_predicate(item))
m_filtered_items.push_back(item);
m_items = &m_filtered_items;
}
template <typename ItemT>
void Menu<ItemT>::reapplyFilter()
{
applyFilter(m_filter_predicate);
}
template <typename ItemT> template <typename TargetT>
const TargetT *Menu<ItemT>::filterPredicate() const
{
return m_filter_predicate.template target<TargetT>();
}
template <typename ItemT>
void Menu<ItemT>::clearFilter()
{
m_filter_predicate = nullptr;
m_filtered_items.clear();
m_items = &m_all_items;
}
}
#endif // NCMPCPP_MENU_IMPL_H

291
src/curses/scrollpad.cpp Normal file
View File

@@ -0,0 +1,291 @@
/***************************************************************************
* Copyright (C) 2008-2016 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. *
***************************************************************************/
#include <cassert>
#include <boost/regex.hpp>
#include <iostream>
#include "scrollpad.h"
namespace {
template <typename PropT>
bool regexSearch(NC::Buffer &buf, PropT begin, const std::string &ws, PropT end, boost::regex::flag_type flags, size_t id)
{
try {
boost::regex rx(ws, flags);
auto first = boost::sregex_iterator(buf.str().begin(), buf.str().end(), rx);
auto last = boost::sregex_iterator();
bool success = first != last;
for (; first != last; ++first)
{
buf.addProperty(first->position(), begin, id);
buf.addProperty(first->position() + first->length(), end, id);
}
return success;
} catch (boost::bad_expression &e) {
std::cerr << "regexSearch: bad_expression: " << e.what() << "\n";
return false;
}
}
}
namespace NC {
Scrollpad::Scrollpad(size_t startx,
size_t starty,
size_t width,
size_t height,
const std::string &title,
Color color,
Border border)
: Window(startx, starty, width, height, title, color, border),
m_beginning(0),
m_real_height(height)
{
}
void Scrollpad::refresh()
{
assert(m_real_height >= m_height);
size_t max_beginning = m_real_height - m_height;
m_beginning = std::min(m_beginning, max_beginning);
prefresh(m_window, m_beginning, 0, m_start_y, m_start_x, m_start_y+m_height-1, m_start_x+m_width-1);
}
void Scrollpad::resize(size_t new_width, size_t new_height)
{
adjustDimensions(new_width, new_height);
recreate(new_width, new_height);
flush();
}
void Scrollpad::scroll(Scroll where)
{
assert(m_real_height >= m_height);
size_t max_beginning = m_real_height - m_height;
switch (where)
{
case Scroll::Up:
{
if (m_beginning > 0)
--m_beginning;
break;
}
case Scroll::Down:
{
if (m_beginning < max_beginning)
++m_beginning;
break;
}
case Scroll::PageUp:
{
if (m_beginning > m_height)
m_beginning -= m_height;
else
m_beginning = 0;
break;
}
case Scroll::PageDown:
{
m_beginning = std::min(m_beginning + m_height, max_beginning);
break;
}
case Scroll::Home:
{
m_beginning = 0;
break;
}
case Scroll::End:
{
m_beginning = max_beginning;
break;
}
}
}
void Scrollpad::clear()
{
m_real_height = m_height;
m_buffer.clear();
werase(m_window);
delwin(m_window);
m_window = newpad(m_height, m_width);
setTimeout(m_window_timeout);
setColor(m_color);
}
const std::string &Scrollpad::buffer()
{
return m_buffer.str();
}
void Scrollpad::flush()
{
auto &w = static_cast<Window &>(*this);
const auto &s = m_buffer.str();
const auto &ps = m_buffer.properties();
auto p = ps.begin();
size_t i = 0;
auto load_properties = [&]() {
for (; p != ps.end() && p->first == i; ++p)
w << p->second;
};
auto write_whitespace = [&]() {
for (; i < s.length() && iswspace(s[i]); ++i)
{
load_properties();
w << s[i];
}
};
auto write_word = [&](bool load_properties_) {
for (; i < s.length() && !iswspace(s[i]); ++i)
{
if (load_properties_)
load_properties();
w << s[i];
}
};
auto write_buffer = [&](bool generate_height_only) -> size_t {
int new_y;
size_t height = 1;
size_t old_i;
auto old_p = p;
int x, y;
i = 0;
p = ps.begin();
y = getY();
while (i < s.length())
{
// write all whitespaces.
write_whitespace();
// if we are generating height, check difference
// between previous Y coord and current one and
// update height accordingly.
if (generate_height_only)
{
new_y = getY();
height += new_y - y;
y = new_y;
}
if (i == s.length())
break;
// save current string position state and get current
// coordinates as we are before the beginning of a word.
old_i = i;
old_p = p;
x = getX();
y = getY();
// write word to test if it overflows, but do not load properties
// yet since if it overflows, we do not want to load them twice.
write_word(false);
// restore previous indexes state
i = old_i;
p = old_p;
// get new Y coord to see if word overflew into next line.
new_y = getY();
if (new_y != y)
{
if (generate_height_only)
{
// if it did, let's update height...
++height;
}
else
{
// ...or go to old coordinates, erase
// part of the string from previous line...
goToXY(x, y);
wclrtoeol(m_window);
}
// ...start at the beginning of next line...
++y;
goToXY(0, y);
// ...write word again, this time with properties...
write_word(true);
if (generate_height_only)
{
// ... and check for potential
// difference in Y coordinates again.
new_y = getY();
height += new_y - y;
}
}
else
{
// word didn't overflow, rewrite it with properties.
goToXY(x, y);
write_word(true);
}
if (generate_height_only)
{
// move to the first line, since when we do
// generation, m_real_height = m_height and we
// don't have many lines to use.
goToXY(getX(), 0);
y = 0;
}
}
// load remaining properties if there are any
for (; p != ps.end(); ++p)
w << p->second;
return height;
};
m_real_height = std::max(write_buffer(true), m_height);
if (m_real_height > m_height)
recreate(m_width, m_real_height);
else
werase(m_window);
write_buffer(false);
}
void Scrollpad::reset()
{
m_beginning = 0;
}
bool Scrollpad::setProperties(Color begin, const std::string &s, Color end, size_t flags, size_t id)
{
return regexSearch(m_buffer, std::move(begin), s, std::move(end), id, flags);
}
bool Scrollpad::setProperties(Format begin, const std::string &s, Format end, size_t flags, size_t id)
{
return regexSearch(m_buffer, begin, s, end, flags, id);
}
void Scrollpad::removeProperties(size_t id)
{
m_buffer.removeProperties(id);
}
}

82
src/curses/scrollpad.h Normal file
View File

@@ -0,0 +1,82 @@
/***************************************************************************
* Copyright (C) 2008-2016 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_SCROLLPAD_H
#define NCMPCPP_SCROLLPAD_H
#include "window.h"
#include "strbuffer.h"
namespace NC {
/// Scrollpad is specialized window that holds large portions of text and
/// supports scrolling if the amount of it is bigger than the window area.
struct Scrollpad: public Window
{
Scrollpad() { }
Scrollpad(size_t startx, size_t starty, size_t width, size_t height,
const std::string &title, Color color, Border border);
// override a few Window functions
virtual void refresh() override;
virtual void scroll(Scroll where) override;
virtual void resize(size_t new_width, size_t new_height) override;
virtual void clear() override;
const std::string &buffer();
void flush();
void reset();
bool setProperties(Color begin, const std::string &s, Color end,
size_t flags, size_t id = -2);
bool setProperties(Format begin, const std::string &s, Format end,
size_t flags, size_t id = -2);
void removeProperties(size_t id = -2);
Scrollpad &operator<<(int n) { return write(n); }
Scrollpad &operator<<(long int n) { return write(n); }
Scrollpad &operator<<(unsigned int n) { return write(n); }
Scrollpad &operator<<(unsigned long int n) { return write(n); }
Scrollpad &operator<<(char c) { return write(c); }
Scrollpad &operator<<(const char *s) { return write(s); }
Scrollpad &operator<<(const std::string &s) { return write(s); }
Scrollpad &operator<<(Color color) { return write(color); }
Scrollpad &operator<<(Format format) { return write(format); }
private:
template <typename ItemT>
Scrollpad &write(ItemT &&item)
{
m_buffer << std::forward<ItemT>(item);
return *this;
}
Buffer m_buffer;
size_t m_beginning;
size_t m_real_height;
};
}
#endif // NCMPCPP_SCROLLPAD_H

209
src/curses/strbuffer.h Normal file
View File

@@ -0,0 +1,209 @@
/***************************************************************************
* Copyright (C) 2008-2016 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_STRBUFFER_H
#define NCMPCPP_STRBUFFER_H
#include <boost/lexical_cast.hpp>
#include <map>
#include "window.h"
namespace NC {
/// Buffer template class that stores text
/// along with its properties (colors/formatting).
template <typename CharT> class BasicBuffer
{
struct Property
{
enum class Type { Color, Format };
Property(NC::Color color_, size_t id_)
: m_type(Type::Color), m_color(std::move(color_)), m_id(id_) { }
Property(NC::Format format_, size_t id_)
: m_type(Type::Format), m_format(format_), m_id(id_) { }
size_t id() const { return m_id; }
template <typename OutputStreamT>
friend OutputStreamT &operator<<(OutputStreamT &os, const Property &p)
{
switch (p.m_type)
{
case Type::Color:
os << p.m_color;
break;
case Type::Format:
os << p.m_format;
break;
}
return os;
}
private:
Type m_type;
Color m_color;
Format m_format;
size_t m_id;
};
public:
typedef std::basic_string<CharT> StringType;
typedef std::multimap<size_t, Property> Properties;
const StringType &str() const { return m_string; }
const Properties &properties() const { return m_properties; }
template <typename PropertyT>
void addProperty(size_t position, PropertyT &&property, size_t id = -1)
{
assert(position <= m_string.size());
m_properties.emplace(position, Property(std::forward<PropertyT>(property), id));
}
void removeProperties(size_t id = -1)
{
auto it = m_properties.begin();
while (it != m_properties.end())
{
if (it->second.id() == id)
m_properties.erase(it++);
else
++it;
}
}
bool empty() const
{
return m_string.empty() && m_properties.empty();
}
void clear()
{
m_string.clear();
m_properties.clear();
}
BasicBuffer<CharT> &operator<<(int n)
{
m_string += boost::lexical_cast<StringType>(n);
return *this;
}
BasicBuffer<CharT> &operator<<(long int n)
{
m_string += boost::lexical_cast<StringType>(n);
return *this;
}
BasicBuffer<CharT> &operator<<(unsigned int n)
{
m_string += boost::lexical_cast<StringType>(n);
return *this;
}
BasicBuffer<CharT> &operator<<(unsigned long int n)
{
m_string += boost::lexical_cast<StringType>(n);
return *this;
}
BasicBuffer<CharT> &operator<<(CharT c)
{
m_string += c;
return *this;
}
BasicBuffer<CharT> &operator<<(const CharT *s)
{
m_string += s;
return *this;
}
BasicBuffer<CharT> &operator<<(const StringType &s)
{
m_string += s;
return *this;
}
BasicBuffer<CharT> &operator<<(Color color)
{
addProperty(m_string.size(), color);
return *this;
}
BasicBuffer<CharT> &operator<<(Format format)
{
addProperty(m_string.size(), format);
return *this;
}
// static variadic initializer. used instead of a proper constructor because
// it's too polymorphic and would end up invoked as a copy/move constructor.
template <typename... Args>
static BasicBuffer init(Args&&... args)
{
BasicBuffer result;
result.construct(std::forward<Args>(args)...);
return result;
}
private:
void construct() { }
template <typename ArgT, typename... Args>
void construct(ArgT &&arg, Args&&... args)
{
*this << std::forward<ArgT>(arg);
construct(std::forward<Args>(args)...);
}
StringType m_string;
Properties m_properties;
};
typedef BasicBuffer<char> Buffer;
typedef BasicBuffer<wchar_t> WBuffer;
template <typename OutputStreamT, typename CharT>
OutputStreamT &operator<<(OutputStreamT &os, const BasicBuffer<CharT> &buffer)
{
if (buffer.properties().empty())
os << buffer.str();
else
{
auto &s = buffer.str();
auto &ps = buffer.properties();
auto p = ps.begin();
for (size_t i = 0;; ++i)
{
for (; p != ps.end() && p->first == i; ++p)
os << p->second;
if (i < s.size())
os << s[i];
else
break;
}
}
return os;
}
}
#endif // NCMPCPP_STRBUFFER_H

1388
src/curses/window.cpp Normal file

File diff suppressed because it is too large Load Diff

537
src/curses/window.h Normal file
View File

@@ -0,0 +1,537 @@
/***************************************************************************
* Copyright (C) 2008-2016 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
#define NCURSES_NOMACROS 1
#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
/// NC namespace provides set of easy-to-use
/// wrappers over original curses library.
namespace NC {
namespace Key {
typedef uint64_t Type;
const Type None = -1;
// modifier masks
const Type Special = Type{1} << 63;
const Type Alt = Type{1} << 62;
const Type Ctrl = Type{1} << 61;
const Type Shift = Type{1} << 60;
// 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;
const Type EoF = Special | 279;
}
/// 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 window's border
void refreshBorder() const;
/// 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);
/// 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