/*************************************************************************** * Copyright (C) 2008-2009 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 _STRBUFFER_H #define _STRBUFFER_H #include "window.h" #include #include namespace NCurses { template class basic_buffer { struct FormatPos { size_t Position; short Value; bool operator<(const FormatPos &f) { return Position < f.Position; } bool operator==(const FormatPos &f) { return Position == f.Position && Value == f.Value; } }; std::basic_ostringstream itsString; std::list itsFormat; std::basic_string *itsTempString; public: basic_buffer() : itsTempString(0) { } basic_buffer(const basic_buffer &b); std::basic_string Str() const; bool SetFormatting(short vb, const std::basic_string &s, short ve, bool for_each = 1); void RemoveFormatting(short vb, const std::basic_string &s, short ve, bool for_each = 1); void SetTemp(std::basic_string *); void Write(Window &w, size_t &pos, size_t width, const std::basic_string &sep); void Clear(); template basic_buffer &operator<<(const T &t) { itsString << t; return *this; } basic_buffer &operator<<(std::ostream &(*os)(std::ostream &)); basic_buffer &operator<<(const Color &color); basic_buffer &operator<<(const Format &f); basic_buffer &operator<<(const basic_buffer &buf); friend Window &operator<< <>(Window &, const basic_buffer &); private: void LoadAttribute(Window &w, short value) const; }; typedef basic_buffer Buffer; typedef basic_buffer WBuffer; } template NCurses::basic_buffer::basic_buffer(const basic_buffer &b) : itsFormat(b.itsFormat), itsTempString(b.itsTempString) { itsString << b.itsString.str(); } template std::basic_string NCurses::basic_buffer::Str() const { return itsString.str(); } template bool NCurses::basic_buffer::SetFormatting(short vb, const std::basic_string &s, short ve, bool for_each) { if (s.empty()) return false; bool result = false; std::basic_string base = itsString.str(); FormatPos fp; for (size_t i = base.find(s); i != std::basic_string::npos; i = base.find(s, i)) { result = true; fp.Value = vb; fp.Position = i; itsFormat.push_back(fp); i += s.length(); fp.Value = ve; fp.Position = i; itsFormat.push_back(fp); if (!for_each) break; } itsFormat.sort(); return result; } template void NCurses::basic_buffer::RemoveFormatting(short vb, const std::basic_string &s, short ve, bool for_each) { if (s.empty()) return; std::basic_string base = itsString.str(); FormatPos fp; for (size_t i = base.find(s); i != std::basic_string::npos; i = base.find(s, i)) { fp.Value = vb; fp.Position = i; itsFormat.remove(fp); i += s.length(); fp.Value = ve; fp.Position = i; itsFormat.remove(fp); if (!for_each) break; } } template void NCurses::basic_buffer::SetTemp(std::basic_string *tmp) { itsTempString = tmp; } template void NCurses::basic_buffer::Write(Window &w, size_t &pos, size_t width, const std::basic_string &sep) { std::basic_string s = itsString.str(); size_t len = Window::Length(s); if (len > width) { s += sep; len = 0; typename std::list::FormatPos>::const_iterator lb = itsFormat.begin(); if (itsFormat.back().Position > pos) // if there is no attributes from current position, don't load them { // load all attributes that are before start position for (; lb->Position < pos; ++lb) LoadAttribute(w, lb->Value); } for (size_t i = pos; i < s.length() && len < width; ++i) { while (i == lb->Position && lb != itsFormat.end()) { LoadAttribute(w, lb->Value); ++lb; } len += wcwidth(s[i]); w << s[i]; } if (++pos >= s.length()) pos = 0; if (len < width) lb = itsFormat.begin(); for (size_t i = 0; len < width; ++i) { while (i == lb->Position && lb != itsFormat.end()) { LoadAttribute(w, lb->Value); ++lb; } len += wcwidth(s[i]); w << s[i]; } // load all remained attributes to clean up for (; lb != itsFormat.end(); ++lb) LoadAttribute(w, lb->Value); } else w << *this; } template void NCurses::basic_buffer::Clear() { itsString.str(std::basic_string()); itsFormat.clear(); } template void NCurses::basic_buffer::LoadAttribute(Window &w, short value) const { if (value < NCurses::fmtNone) w << NCurses::Color(value); else w << NCurses::Format(value); } template NCurses::basic_buffer &NCurses::basic_buffer::operator<<(std::ostream &(*os)(std::ostream&)) { itsString << os; return *this; } template NCurses::basic_buffer &NCurses::basic_buffer::operator<<(const Color &color) { FormatPos f; f.Position = itsString.str().length(); f.Value = color; itsFormat.push_back(f); return *this; } template NCurses::basic_buffer &NCurses::basic_buffer::operator<<(const Format &f) { return operator<<(Color(f)); } template NCurses::basic_buffer &NCurses::basic_buffer::operator<<(const NCurses::basic_buffer &buf) { size_t len = itsString.str().length(); itsString << buf.itsString.str(); std::list tmp = buf.itsFormat; if (len) for (typename std::list::FormatPos>::iterator it = tmp.begin(); it != tmp.end(); ++it) it->Position += len; itsFormat.merge(tmp); return *this; } template NCurses::Window &operator<<(NCurses::Window &w, const NCurses::basic_buffer &buf) { const std::basic_string &s = buf.itsTempString ? *buf.itsTempString : buf.itsString.str(); if (buf.itsFormat.empty()) { w << s; } else { std::basic_string tmp; typename std::list::FormatPos>::const_iterator b = buf.itsFormat.begin(); typename std::list::FormatPos>::const_iterator e = buf.itsFormat.end(); for (size_t i = 0; i < s.length() || b != e; ++i) { while (b != e && i == b->Position) { if (!tmp.empty()) { w << tmp; tmp.clear(); } buf.LoadAttribute(w, b->Value); b++; } if (i < s.length()) tmp += s[i]; } if (!tmp.empty()) w << tmp; } return w; } #endif