diff --git a/ChangeLog b/ChangeLog index 628f9f5a..40781480 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-07-11 Markus Gans + * New class FTermBuffer to buffer terminal outputs + * Add the possibility to print from the terminal buffer + 2017-07-03 Markus Gans * Use more static const variables where it makes sense diff --git a/src/Makefile.am b/src/Makefile.am index 8973f59a..16b4ea73 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,6 +43,7 @@ libfinal_la_SOURCES = \ fevent.cpp \ foptiattr.cpp \ foptimove.cpp \ + ftermbuffer.cpp \ fapp.cpp \ fwidget.cpp \ fobject.cpp @@ -81,6 +82,7 @@ finalcutinclude_HEADERS = \ fpoint.h \ foptiattr.h \ foptimove.h \ + ftermbuffer.h \ fprogressbar.h \ fradiobutton.h \ frect.h \ diff --git a/src/Makefile.clang b/src/Makefile.clang index 8f8eb7fb..a58ade3a 100644 --- a/src/Makefile.clang +++ b/src/Makefile.clang @@ -30,6 +30,7 @@ INCLUDE_HEADERS = \ fobject.h \ foptiattr.h \ foptimove.h \ + ftermbuffer.h \ fpoint.h \ fprogressbar.h \ fradiobutton.h \ @@ -91,6 +92,7 @@ OBJS = \ fevent.o \ foptiattr.o \ foptimove.o \ + ftermbuffer.o \ fapp.o \ fwidget.o \ fobject.o diff --git a/src/Makefile.gcc b/src/Makefile.gcc index d0ac059f..534f56ef 100644 --- a/src/Makefile.gcc +++ b/src/Makefile.gcc @@ -30,6 +30,7 @@ INCLUDE_HEADERS = \ fobject.h \ foptiattr.h \ foptimove.h \ + ftermbuffer.h \ fpoint.h \ fprogressbar.h \ fradiobutton.h \ @@ -91,6 +92,7 @@ OBJS = \ fevent.o \ foptiattr.o \ foptimove.o \ + ftermbuffer.o \ fapp.o \ fwidget.o \ fobject.o diff --git a/src/Makefile.in b/src/Makefile.in index 177b514c..4af7fc6b 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -135,8 +135,8 @@ am_libfinal_la_OBJECTS = fstring.lo fpoint.lo frect.lo fscrollbar.lo \ fmenuitem.lo fradiomenuitem.lo fcheckmenuitem.lo fmenulist.lo \ fdialog.lo fscrollview.lo fwindow.lo fmessagebox.lo \ ftooltip.lo ffiledialog.lo ftextview.lo fstatusbar.lo fterm.lo \ - fvterm.lo fevent.lo foptiattr.lo foptimove.lo fapp.lo \ - fwidget.lo fobject.lo + fvterm.lo fevent.lo foptiattr.lo foptimove.lo ftermbuffer.lo \ + fapp.lo fwidget.lo fobject.lo libfinal_la_OBJECTS = $(am_libfinal_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -409,6 +409,7 @@ libfinal_la_SOURCES = \ fevent.cpp \ foptiattr.cpp \ foptimove.cpp \ + ftermbuffer.cpp \ fapp.cpp \ fwidget.cpp \ fobject.cpp @@ -445,6 +446,7 @@ finalcutinclude_HEADERS = \ fpoint.h \ foptiattr.h \ foptimove.h \ + ftermbuffer.h \ fprogressbar.h \ fradiobutton.h \ frect.h \ @@ -571,6 +573,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fstring.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fswitch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fterm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftermbuffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftextview.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftogglebutton.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftooltip.Plo@am__quote@ diff --git a/src/ffiledialog.cpp b/src/ffiledialog.cpp index d81376b2..0745d901 100644 --- a/src/ffiledialog.cpp +++ b/src/ffiledialog.cpp @@ -473,7 +473,7 @@ void FFileDialog::init() static const int h = 15; int x, y; FWidget* parent_widget; - + setGeometry(1, 1, w, h, false); parent_widget = getParentWidget(); diff --git a/src/ftermbuffer.cpp b/src/ftermbuffer.cpp new file mode 100644 index 00000000..52533def --- /dev/null +++ b/src/ftermbuffer.cpp @@ -0,0 +1,141 @@ +// File: ftermbuffer.cpp +// Provides: class FTermBuffer + +#include "ftermbuffer.h" + + +//---------------------------------------------------------------------- +// class FTermBuffer +//---------------------------------------------------------------------- + +// constructors and destructor +//---------------------------------------------------------------------- +FTermBuffer::FTermBuffer() + : data() +{ } + +//---------------------------------------------------------------------- +FTermBuffer::~FTermBuffer() // destructor +{ } + + +// public methods of FTermBuffer +//---------------------------------------------------------------------- +int FTermBuffer::writef (const wchar_t* format, ...) +{ + assert ( format != 0 ); + static const int buf_size = 1024; + wchar_t buffer[buf_size]; + va_list args; + + va_start (args, format); + std::vswprintf (buffer, buf_size, format, args); + va_end (args); + + FString str(buffer); + return write(str); +} + +//---------------------------------------------------------------------- +int FTermBuffer::writef (const char* format, ...) +{ + assert ( format != 0 ); + int len; + char buf[512]; + char* buffer; + va_list args; + + buffer = buf; + va_start (args, format); + len = vsnprintf (buffer, sizeof(buf), format, args); + va_end (args); + + if ( len >= int(sizeof(buf)) ) + { + buffer = new char[len+1](); + va_start (args, format); + vsnprintf (buffer, uLong(len+1), format, args); + va_end (args); + } + + FString str(buffer); + int ret = write(str); + + if ( buffer != buf ) + delete[] buffer; + + return ret; +} + +//---------------------------------------------------------------------- +int FTermBuffer::write (const std::wstring& s) +{ + assert ( ! s.empty() ); + return write (FString(s)); +} + +//---------------------------------------------------------------------- +int FTermBuffer::write (const wchar_t* s) +{ + assert ( s != 0 ); + return write (FString(s)); +} + +//---------------------------------------------------------------------- +int FTermBuffer::write (const char* s) +{ + assert ( s != 0 ); + FString str(s); + return write(str); +} + +//---------------------------------------------------------------------- +int FTermBuffer::write (const std::string& s) +{ + assert ( ! s.empty() ); + return write (FString(s)); +} + +//---------------------------------------------------------------------- +int FTermBuffer::write (const FString& s) +{ + assert ( ! s.isNull() ); + register int len = 0; + const wchar_t* p = s.wc_str(); + + if ( p ) + { + while ( *p ) + { + char_data nc; // next character + nc = FVTerm::getAttribute(); + nc.code = *p; + nc.no_changes = false; + nc.printed = false; + + data.push_back(nc); + + p++; + len++; + } // end of while + } + + return len; +} + +//---------------------------------------------------------------------- +int FTermBuffer::write (register int c) +{ + char_data nc; // next character + nc = FVTerm::getAttribute(); + nc.code = c; + nc.no_changes = false; + nc.printed = false; + + data.push_back(nc); + return 1; +} + + +// private methods of FTermBuffer +//---------------------------------------------------------------------- diff --git a/src/ftermbuffer.h b/src/ftermbuffer.h new file mode 100644 index 00000000..59ead670 --- /dev/null +++ b/src/ftermbuffer.h @@ -0,0 +1,112 @@ +// File: ftermbuffer.h +// Provides: class FTermBuffer +// +// Standalone class +// ════════════════ +// +// ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▏ +// ▕ FTermBuffer ▏ +// ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▏ + + +#ifndef FTERMBUFFER_H +#define FTERMBUFFER_H + +#include +#include // std::stringstream + +#include "fvterm.h" +#include "fstring.h" + + +//---------------------------------------------------------------------- +// class FTermBuffer +//---------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) + +class FTermBuffer +{ + public: + // Typedef + typedef FOptiAttr::char_data char_data; + + // Constructor + explicit FTermBuffer(); + + // Destructor + virtual ~FTermBuffer(); + + // Overloaded operators + template FTermBuffer& operator << (const type&); + + // Accessors + virtual const char* getClassName() const; + int getLength() const; + + // Inquiry + bool isEmpty () const; + + // Methods + void clear(); + int writef (const wchar_t*, ...); + int writef (const char*, ...) + #if defined(__clang__) + __attribute__((__format__ (__printf__, 2, 3))) + #elif defined(__GNUC__) + __attribute__ ((format (printf, 2, 3))) + #endif + ; + int write (const std::wstring&); + int write (const wchar_t*); + int write (const char*); + int write (const std::string&); + int write (const FString&); + int write (int); + FTermBuffer& write (); + std::vector getBuffer(); + + private: + std::vector data; +}; + +#pragma pack(pop) + + +// FTermBuffer inline functions +//---------------------------------------------------------------------- +template +inline FTermBuffer& FTermBuffer::operator << (const type& s) +{ + std::ostringstream outstream; + outstream << s; + write (outstream.str()); + return *this; +} + +//---------------------------------------------------------------------- +inline const char* FTermBuffer::getClassName() const +{ return "FTermBuffer"; } + +//---------------------------------------------------------------------- +inline int FTermBuffer::getLength() const +{ return int(data.size()); } + +//---------------------------------------------------------------------- +inline bool FTermBuffer::isEmpty() const +{ return data.empty(); } + +//---------------------------------------------------------------------- +inline void FTermBuffer::clear() +{ data.clear(); } + +//---------------------------------------------------------------------- +inline FTermBuffer& FTermBuffer::write() +{ return *this; } + +//---------------------------------------------------------------------- +inline std::vector FTermBuffer::getBuffer() +{ return data; } + +#endif // FTERMBUFFER_H diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 2bbb63fd..8c486062 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -552,6 +552,142 @@ int FVTerm::print (term_area* area, const FString& s) return len; } +//---------------------------------------------------------------------- +int FVTerm::print (const std::vector& termString) +{ + if ( termString.empty() ) + return 0; + + term_area* area = getPrintArea(); + + if ( ! area ) + { + if ( vdesktop ) + area = vdesktop; + else + return -1; + } + + return print (area, termString); +} + +//---------------------------------------------------------------------- +int FVTerm::print (term_area* area, const std::vector& termString) +{ + register int len = 0; + std::vector::const_iterator iter; + iter = termString.begin(); + uInt tabstop = uInt(getTabstop()); + + if ( ! area ) + return -1; + + if ( termString.empty() ) + return 0; + else + area->has_changes = true; + + while ( iter != termString.end() ) + { + int width, height, rsh, bsh; + width = area->width; + height = area->height; + rsh = area->right_shadow; + bsh = area->bottom_shadow; + + switch ( (*iter).code ) + { + case '\n': + area->cursor_y++; + + case '\r': + area->cursor_x = 1; + break; + + case '\t': + area->cursor_x = short ( uInt(area->cursor_x) + + tabstop + - uInt(area->cursor_x) + + 1 + % tabstop ); + break; + + case '\b': + area->cursor_x--; + break; + + case '\a': + beep(); + break; + + default: + { + int ax = area->cursor_x - 1; + int ay = area->cursor_y - 1; + + char_data nc = *iter; // next character + + if ( area + && area->cursor_x > 0 + && area->cursor_y > 0 + && ax < area->width + area->right_shadow + && ay < area->height + area->bottom_shadow ) + { + char_data* ac; // area character + int line_len = area->width + area->right_shadow; + ac = &area->text[ay * line_len + ax]; + + if ( *ac != nc ) // compare with an overloaded operator + { + if ( ( ! ac->transparent && nc.transparent ) + || ( ! ac->trans_shadow && nc.trans_shadow ) + || ( ! ac->inherit_bg && nc.inherit_bg ) ) + { + // add one transparent character form line + area->changes[ay].trans_count++; + } + else if ( ( ac->transparent && ! nc.transparent ) + || ( ac->trans_shadow && ! nc.trans_shadow ) + || ( ac->inherit_bg && ! nc.inherit_bg ) ) + { + // remove one transparent character from line + area->changes[ay].trans_count--; + } + + // copy character to area + std::memcpy (ac, &nc, sizeof(nc)); + + if ( ax < short(area->changes[ay].xmin) ) + area->changes[ay].xmin = uInt(ax); + + if ( ax > short(area->changes[ay].xmax) ) + area->changes[ay].xmax = uInt(ax); + } + } + + area->cursor_x++; + } + } + + if ( area->cursor_x > width + rsh ) + { + area->cursor_x = 1; + area->cursor_y++; + } + + if ( area->cursor_y > height + bsh ) + { + area->cursor_y--; + break; + } + + len++; + ++iter; + } // end of while + + return len; +} + //---------------------------------------------------------------------- int FVTerm::print (register int c) { diff --git a/src/fvterm.h b/src/fvterm.h index 15541081..a91d768b 100644 --- a/src/fvterm.h +++ b/src/fvterm.h @@ -140,6 +140,7 @@ class FVTerm : public FObject, public FTerm static short getTermBackgroundColor(); term_area* getVWin() const; FPoint getPrintCursor(); + static char_data getAttribute(); // Mutators static void setTermXY (register int, register int); @@ -265,6 +266,8 @@ class FVTerm : public FObject, public FTerm int print (term_area*, const std::string&); int print (const FString&); int print (term_area*, const FString&); + int print (const std::vector&); + int print (term_area*, const std::vector&); int print (int); int print (term_area*, int); FVTerm& print(); @@ -443,6 +446,10 @@ inline short FVTerm::getTermBackgroundColor() inline FVTerm::term_area* FVTerm::getVWin() const { return vwin; } +//---------------------------------------------------------------------- +inline FVTerm::char_data FVTerm::getAttribute() +{ return next_attribute; } + //---------------------------------------------------------------------- inline bool FVTerm::hideCursor() { return hideCursor(true); }