/*************************************************************************** * Copyright (C) 2008-2014 by Andrzej Rybczak * * electricityispower@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef NCMPCPP_STRBUFFER_H #define NCMPCPP_STRBUFFER_H #include #include #include "window.h" namespace NC { /// Buffer template class that stores text /// along with its properties (colors/formatting). template class BasicBuffer { struct Property { enum class Type { Color, Format }; Property(size_t position_, NC::Color color_, int id_) : m_type(Type::Color), m_position(position_), m_color(std::move(color_)), m_id(id_) { } Property(size_t position_, NC::Format format_, int id_) : m_type(Type::Format), m_position(position_), m_format(format_), m_id(id_) { } size_t position() const { return m_position; } size_t id() const { return m_id; } bool operator<(const Property &rhs) const { if (m_position != rhs.m_position) return m_position < rhs.m_position; if (m_type != rhs.m_type) return m_type < rhs.m_type; switch (m_type) { case Type::Color: if (m_color != rhs.m_color) return m_color < rhs.m_color; break; case Type::Format: if (m_format != rhs.m_format) return m_format < rhs.m_format; break; } return m_id < rhs.m_id; } template 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; size_t m_position; Color m_color; Format m_format; size_t m_id; }; public: typedef std::basic_string StringType; typedef std::multiset Properties; const StringType &str() const { return m_string; } const Properties &properties() const { return m_properties; } template void setProperty(size_t position, PropertyT &&property, size_t id = -1) { m_properties.insert(Property(position, std::forward(property), id)); } template bool removeProperty(size_t position, PropertyT &&property, size_t id = -1) { auto it = m_properties.find(Property(position, std::forward(property), id)); bool found = it != m_properties.end(); if (found) m_properties.erase(it); return found; } void removeProperties(size_t id = -1) { auto it = m_properties.begin(); while (it != m_properties.end()) { if (it->id() == id) m_properties.erase(it++); else ++it; } } void clear() { m_string.clear(); m_properties.clear(); } BasicBuffer &operator<<(int n) { m_string += boost::lexical_cast(n); return *this; } BasicBuffer &operator<<(long int n) { m_string += boost::lexical_cast(n); return *this; } BasicBuffer &operator<<(unsigned int n) { m_string += boost::lexical_cast(n); return *this; } BasicBuffer &operator<<(unsigned long int n) { m_string += boost::lexical_cast(n); return *this; } BasicBuffer &operator<<(CharT c) { m_string += c; return *this; } BasicBuffer &operator<<(const CharT *s) { m_string += s; return *this; } BasicBuffer &operator<<(const StringType &s) { m_string += s; return *this; } BasicBuffer &operator<<(Color color) { setProperty(m_string.size(), color); return *this; } BasicBuffer &operator<<(Format format) { setProperty(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 static BasicBuffer init(Args&&... args) { BasicBuffer result; result.construct(std::forward(args)...); return result; } private: void construct() { } template void construct(ArgT &&arg, Args&&... args) { *this << std::forward(arg); construct(std::forward(args)...); } StringType m_string; Properties m_properties; }; typedef BasicBuffer Buffer; typedef BasicBuffer WBuffer; template OutputStreamT &operator<<(OutputStreamT &os, const BasicBuffer &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 < s.size(); ++i) { for (; p != ps.end() && p->position() == i; ++p) os << *p; os << s[i]; } // load remaining properties for (; p != ps.end(); ++p) os << *p; } return os; } } #endif // NCMPCPP_STRBUFFER_H