/*************************************************************************** * 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 { /// Buffer template class that can store text along with its /// format attributes. The content can be easily printed to /// window or taken as raw string at any time. /// template class basic_buffer { /// Struct used for storing information about /// one color/format flag along with its position /// 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; } }; /// Internal buffer for storing raw text /// std::basic_ostringstream itsString; /// List used for storing formatting informations /// std::list itsFormat; /// Pointer to temporary string /// @see SetTemp() /// std::basic_string *itsTempString; public: /// Constructs an empty buffer /// basic_buffer() : itsTempString(0) { } /// Constructs a buffer from the existed one /// @param b copied buffer /// basic_buffer(const basic_buffer &b); /// @return raw content of the buffer without formatting informations /// std::basic_string Str() const; /// Searches for given string in buffer and sets format/color at the /// beginning and end of it using val_b and val_e flags accordingly /// @param val_b flag set at the beginning of found occurence of string /// @param s string that function seaches for /// @param val_e flag set at the end of found occurence of string /// @param for_each indicates whether function searches through whole buffer and sets /// the format for all occurences of given string or stops after the first one /// @return true if at least one occurence of the string was found, false otherwise /// bool SetFormatting(short val_b, const std::basic_string &s, short val_e, bool for_each = 1); /// Searches for given string in buffer and removes given /// format/color from the beginning and end of its occurence /// @param val_b flag to be removed from the beginning of the string /// @param s string that function seaches for /// @param val_e flag to be removed from the end of the string /// @param for_each indicates whether function searches through whole buffer and removes /// given format from all occurences of given string or stops after the first one /// void RemoveFormatting(short val_b, const std::basic_string &s, short val_e, bool for_each = 1); /// Sets the pointer to string, that will be passed in operator<<() to window /// object instead of the internal buffer. This is useful if you took the content /// of the buffer, modified it somehow and want to print the modified version instead /// of the original one, but with the original formatting informations. Note that after /// you're done with the printing etc., this pointer has to be set to null. /// @param tmp address of the temporary string /// void SetTemp(std::basic_string *tmp); /// Prints to window object given part of the string, loading all needed formatting info /// and cleaning up after. The main goal of this function is to provide interface for /// colorful scrollers. /// @param w window object that we want to print to /// @param start_pos reference to start position of the string. note that this variable is /// incremented by one after each call or set to 0 if end of string is reached /// @param width width of the string to be printed /// @param separator additional text to be placed between the end and the beginning of /// the string /// void Write(Window &w, size_t &start_pos, size_t width, const std::basic_string &separator) const; /// Clears the content of the buffer and its formatting informations /// void Clear(); /// @param t any object that has defined ostream &operator<<() /// @return reference to itself /// template basic_buffer &operator<<(const T &t) { itsString << t; return *this; } /// Handles colors /// @return reference to itself /// basic_buffer &operator<<(Color color); /// Handles format flags /// @return reference to itself /// basic_buffer &operator<<(Format f); /// Handles copying one buffer to another using operator<<() /// @param buf buffer to be copied /// @return reference to itself /// basic_buffer &operator<<(const basic_buffer &buf); /// Friend operator, that handles printing /// the content of buffer to window object friend Window &operator<< <>(Window &, const basic_buffer &); private: /// Loads an attribute to given window object /// @param w window object we want to load attribute to /// @param value value of attribute to be loaded /// void LoadAttribute(Window &w, short value) const; }; /// Standard buffer that uses narrow characters /// typedef basic_buffer Buffer; /// Standard buffer that uses wide characters /// 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 val_b, const std::basic_string &s, short val_e, 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 = val_b; fp.Position = i; itsFormat.push_back(fp); i += s.length(); fp.Value = val_e; fp.Position = i; itsFormat.push_back(fp); if (!for_each) break; } itsFormat.sort(); return result; } template void NCurses::basic_buffer::RemoveFormatting( short val_b, const std::basic_string &s, short val_e, 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 = val_b; fp.Position = i; itsFormat.remove(fp); i += s.length(); fp.Value = val_e; 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 &start_pos, size_t width, const std::basic_string &separator ) const { std::basic_string s = itsString.str(); size_t len = Window::Length(s); if (len > width) { s += separator; len = 0; typename std::list::FormatPos>::const_iterator lb = itsFormat.begin(); if (itsFormat.back().Position > start_pos) // if there is no attributes from current position, don't load them { // load all attributes that are before start position for (; lb->Position < start_pos; ++lb) LoadAttribute(w, lb->Value); } for (size_t i = start_pos; i < s.length() && len < width; ++i) { while (i == lb->Position && lb != itsFormat.end()) { LoadAttribute(w, lb->Value); ++lb; } if ((len += wcwidth(s[i])) > width) break; w << s[i]; } if (++start_pos >= s.length()) start_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; } if ((len += wcwidth(s[i])) > width) break; 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<<(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<<(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