Move ncurses related files to curses directory
This commit is contained in:
524
src/curses/menu.h
Normal file
524
src/curses/menu.h
Normal 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
398
src/curses/menu_impl.h
Normal 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
291
src/curses/scrollpad.cpp
Normal 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
82
src/curses/scrollpad.h
Normal 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
209
src/curses/strbuffer.h
Normal 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
1388
src/curses/window.cpp
Normal file
File diff suppressed because it is too large
Load Diff
537
src/curses/window.h
Normal file
537
src/curses/window.h
Normal 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
|
||||
Reference in New Issue
Block a user