From 6b9336d6c11976a4f5180935bb2611928d515b4b Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Sun, 29 Sep 2019 22:28:58 +0200 Subject: [PATCH] Streaming into an FTextView() object --- ChangeLog | 7 +++ README.md | 4 +- debian/libfinal-examples.install | 9 +-- debian/libfinal-examples.links | 3 +- debian/rules | 1 + doc/readme.txt | 4 +- examples/calculator.cpp | 4 +- examples/fullwidth-character.cpp | 2 +- examples/opti-move.cpp | 32 +++++----- src/fapplication.cpp | 2 +- src/fcharmap.cpp | 7 +-- src/flineedit.cpp | 2 +- src/flistview.cpp | 6 +- src/fmenubar.cpp | 1 - src/fstring.cpp | 24 ++++++- src/fterm.cpp | 44 ++++++++----- src/ftermdetection.cpp | 7 ++- src/ftextview.cpp | 49 ++++++++------- src/fvterm.cpp | 3 +- src/include/final/fcharmap.h | 2 +- src/include/final/flistview.h | 3 + src/include/final/foptimove.h | 1 - src/include/final/fstring.h | 22 ++++--- src/include/final/fterm.h | 16 +++-- src/include/final/ftermbuffer.h | 11 +--- src/include/final/ftextview.h | 42 +++++++++++++ src/include/final/fvterm.h | 11 +--- test/fstring-test.cpp | 22 ++++++- test/ftermfreebsd-test.cpp | 105 ++++++++++++++++++++----------- 29 files changed, 290 insertions(+), 156 deletions(-) diff --git a/ChangeLog b/ChangeLog index 857ac33f..619a34eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2019-09-29 Markus Gans + * Streaming into an FTextView() object + * Fixes the streaming of empty FString objects into a stream with + a width > 0 + * The FString operator [] now returns a null character ('\0') + if the position is equal to the string length + 2019-09-28 Markus Gans * Support for displaying full-width characters (2 columns wide) on the terminal. This is particularly important for the correct diff --git a/README.md b/README.md index b9b1b04f..7251377c 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,12 @@ The Final Cut FProgressbar widget: Scrollable text in the FTextView widget: - ![FTextView](doc/textview.png) +![FTextView](doc/textview.png) The Mandelbrot set example: - ![Mandelbrot set](doc/Mandelbrot.png) +![Mandelbrot set](doc/Mandelbrot.png) newfont diff --git a/debian/libfinal-examples.install b/debian/libfinal-examples.install index e9789ea4..017b704a 100644 --- a/debian/libfinal-examples.install +++ b/debian/libfinal-examples.install @@ -1,4 +1,5 @@ -examples/.libs/* usr/share/doc/libfinal-examples/examples -examples/*.cpp usr/share/doc/libfinal-examples/examples -examples/Makefile.clang usr/share/doc/libfinal-examples/examples -examples/Makefile.gcc usr/share/doc/libfinal-examples/examples +doc/readme.txt usr/lib/libfinal/examples +examples/.libs/* usr/lib/libfinal/examples +examples/*.cpp usr/lib/libfinal/examples +examples/Makefile.clang usr/lib/libfinal/examples +examples/Makefile.gcc usr/lib/libfinal/examples diff --git a/debian/libfinal-examples.links b/debian/libfinal-examples.links index e6a3b901..d2bcc847 100644 --- a/debian/libfinal-examples.links +++ b/debian/libfinal-examples.links @@ -1 +1,2 @@ -usr/share/doc/libfinal-examples/examples/Makefile.gcc usr/share/doc/libfinal-examples/examples/Makefile +usr/lib/libfinal/examples usr/share/doc/libfinal-examples/examples +usr/lib/libfinal/examples/Makefile.gcc usr/lib/libfinal/examples/Makefile diff --git a/debian/rules b/debian/rules index 3243b57b..24e9348a 100755 --- a/debian/rules +++ b/debian/rules @@ -19,6 +19,7 @@ include /usr/share/dpkg/default.mk # main packaging script based on dh7 syntax %: + sed -i 's/doc\///g' README.md dh $@ --with autotools-dev # debmake generated override targets diff --git a/doc/readme.txt b/doc/readme.txt index 2f185b57..57f413bf 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -1,8 +1,8 @@ ---------------------------------------------------------------------- - The Final Cut + FINAL CUT ---------------------------------------------------------------------- -The Final Cut is a C++ class library and widget toolkit with full mouse +The FINAL CUT is a C++ class library and widget toolkit with full mouse support for creating a text-based user interface. The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple text windows on the screen. diff --git a/examples/calculator.cpp b/examples/calculator.cpp index e7bdf3e4..da963f05 100644 --- a/examples/calculator.cpp +++ b/examples/calculator.cpp @@ -898,9 +898,7 @@ lDouble& Calc::getValue() //---------------------------------------------------------------------- void Calc::setDisplay (lDouble d) { - char buffer[33]{}; - snprintf (buffer, sizeof(buffer), "%32.11Lg", d); - input = buffer; + input.sprintf("%32.11Lg", d); } //---------------------------------------------------------------------- diff --git a/examples/fullwidth-character.cpp b/examples/fullwidth-character.cpp index 7b379d64..533e178d 100644 --- a/examples/fullwidth-character.cpp +++ b/examples/fullwidth-character.cpp @@ -74,9 +74,9 @@ int main (int argc, char* argv[]) scroll_text.setGeometry (FPoint(2, 8), FSize(32, 3)); finalcut::FString text_line{"FINAL CUT supports " "full-width characters."}; + scroll_text << full(text_line); scroll_text.setStatusbarMessage ("You can scroll right and " "left with the arrow keys"); - scroll_text.append(full(text_line)); // Create a OK button finalcut::FButton btn("&OK", &dgl); diff --git a/examples/opti-move.cpp b/examples/opti-move.cpp index 54c0316f..14f40591 100644 --- a/examples/opti-move.cpp +++ b/examples/opti-move.cpp @@ -87,8 +87,7 @@ void term_boundaries (int& x, int& y) void move (int xold, int yold, int xnew, int ynew) { // prints the cursor move escape sequence - std::string sequence{}; - char from[26]{}, to[26]{}, byte[20]{}; + finalcut::FString buffer{}, sequence{}, from{}, to{}, byte{}; const std::string ctrl_character[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", @@ -100,36 +99,33 @@ void move (int xold, int yold, int xnew, int ynew) term_boundaries(xold, yold); term_boundaries(xnew, ynew); - snprintf (from, sizeof(from), "(%3d;%3d)", xold, yold); - snprintf (to, sizeof(to), "(%3d;%3d)", xnew, ynew); - std::cout << std::right << std::setw(10) << from - << " -> " - << std::left << std::setw(10) << to - << " "; + // get the move string - char* buffer = finalcut::FTerm::moveCursorString (xold, yold, xnew, ynew); - uInt len = uInt(std::strlen(buffer)); + buffer = finalcut::FTerm::moveCursorString (xold, yold, xnew, ynew); - for (uInt i = 0; i < len; i++) + for (auto&& ch : buffer) { - char ch = buffer[i]; - if ( ch < 0x21 ) - sequence += ctrl_character[uInt(ch)]; + sequence += ctrl_character[std::size_t(ch)]; else sequence += ch; sequence += ' '; } - std::cout << std::setw(21) << sequence << " "; + from.sprintf ("(%3d;%3d)", xold, yold); + to.sprintf ("(%3d;%3d)", xnew, ynew); + std::size_t len = buffer.getLength(); if ( len <= 1 ) - snprintf (byte, sizeof(byte), "%d byte ", len); + byte.sprintf ("%d byte ", len); else - snprintf (byte, sizeof(byte), "%d bytes", len); + byte.sprintf ("%d bytes", len); - std::cout << std::right << std::setw(10) << byte << "\r\n"; + std::cout << std::right << std::setw(10) << from << " -> " + << std::left << std::setw(10) << to << " " + << std::setw(21) << sequence << " " + << std::right << std::setw(10) << byte << "\r\n"; } diff --git a/src/fapplication.cpp b/src/fapplication.cpp index fe496998..156b503d 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -425,7 +425,7 @@ void FApplication::cmd_options (const int& argc, char* argv[]) {C_STR("no-esc-for-alt-meta"), no_argument, 0, 0 }, #endif - {0, 0, 0, 0 } + {nullptr, 0, nullptr, 0 } }; opterr = 0; diff --git a/src/fcharmap.cpp b/src/fcharmap.cpp index c8ae3e22..dc8cff80 100644 --- a/src/fcharmap.cpp +++ b/src/fcharmap.cpp @@ -144,8 +144,7 @@ uInt character[][fc::NUM_OF_ENCODINGS] = {0x1af4, 0, 0xf4, 0}, // ] - NF_rev_menu_button3 (2) {0x1af5, 0, 0xf5, 0}, // ] - NF_shadow_box_right (2) {0x1afb, 0, 0xfb, 0}, // ✓ - NF_check_mark (2) - {0x221a, 0, 0xfb, 'x'}, // √ - square root - {0x25cf, '`', 0x04, '*'} // ● - black circle + {0x221a, 0, 0xfb, 'x'} // √ - square root }; /* @@ -204,7 +203,7 @@ const std::size_t lastKeyItem = \ std::size_t((sizeof(vt100_key_to_utf8) / sizeof(vt100_key_to_utf8[0])) - 1); -wchar_t cp437_to_ucs[][2] = +wchar_t cp437_ucs[][2] = { {0x00, 0x0000}, // null {0x01, 0x263a}, // white smiling face @@ -465,7 +464,7 @@ wchar_t cp437_to_ucs[][2] = }; const std::size_t lastCP437Item = \ - std::size_t((sizeof(cp437_to_ucs) / sizeof(cp437_to_ucs[0])) - 1); + std::size_t((sizeof(cp437_ucs) / sizeof(cp437_ucs[0])) - 1); // Based on http://www.unicode.org/charts/PDF/UFF00.pdf wchar_t halfWidth_fullWidth[][2] = diff --git a/src/flineedit.cpp b/src/flineedit.cpp index 1ec15632..5c865821 100644 --- a/src/flineedit.cpp +++ b/src/flineedit.cpp @@ -825,7 +825,7 @@ inline FLineEdit::offsetPair FLineEdit::endPosToOffset (std::size_t pos) { if ( char_width == 1 ) { - if ( pos > 0 && getColumnWidth(text[pos - 1]) == 2 ) + if ( getColumnWidth(text[pos - 1]) == 2 ) // pos is always > 0 { fullwidth_char_offset = 1; break; diff --git a/src/flistview.cpp b/src/flistview.cpp index 3b676bcc..84441213 100644 --- a/src/flistview.cpp +++ b/src/flistview.cpp @@ -1648,10 +1648,7 @@ void FListView::drawListLine ( const FListViewItem* item width -= (indent + 1); if ( item->isCheckable() ) - { - static constexpr std::size_t checkbox_space = 4; width -= checkbox_space; - } } // Insert alignment spaces @@ -1999,7 +1996,6 @@ void FListView::updateDrawing (bool draw_vbar, bool draw_hbar) std::size_t FListView::determineLineWidth (FListViewItem* item) { static constexpr std::size_t padding_space = 1; - static constexpr std::size_t checkbox_space = 4; std::size_t line_width = padding_space; // leading space std::size_t column_idx{0}; std::size_t entries = std::size_t(item->column_list.size()); @@ -2109,7 +2105,7 @@ void FListView::recalculateVerticalBar (std::size_t element_count) void FListView::mouseHeaderClicked() { int column{1}; - int checkbox_offset = ( hasCheckableItems() ) ? 4 : 0; + int checkbox_offset = ( hasCheckableItems() ) ? checkbox_space : 0; int header_start = 2 + checkbox_offset; int header_pos = clicked_header_pos.getX() + xoffset; diff --git a/src/fmenubar.cpp b/src/fmenubar.cpp index b9eac303..cd7d46f1 100644 --- a/src/fmenubar.cpp +++ b/src/fmenubar.cpp @@ -534,7 +534,6 @@ inline void FMenuBar::drawItem (FMenuItem* menuitem, std::size_t& x) if ( hotkeypos != NOT_SET ) { - txt_length--; column_width--; to_char--; } diff --git a/src/fstring.cpp b/src/fstring.cpp index eefe3dfe..836487df 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -30,6 +30,10 @@ namespace finalcut { +// static class attributes +wchar_t FString::null_char{L'\0'}; +const wchar_t FString::const_null_char{L'\0'}; + //---------------------------------------------------------------------- // class FString //---------------------------------------------------------------------- @@ -1710,8 +1714,17 @@ const FString operator + (const FString& s, const char c) //---------------------------------------------------------------------- std::ostream& operator << (std::ostream& outstr, const FString& s) { + const std::size_t width = std::size_t(outstr.width()); + if ( s.length > 0 ) - outstr << s.wc_to_c_str( s.string ); + { + outstr << s.wc_to_c_str(s.string); + } + else if ( width > 0 ) + { + FString fill_str(width, outstr.fill()); + outstr << s.wc_to_c_str(fill_str.string); + } return outstr; } @@ -1735,8 +1748,17 @@ std::istream& operator >> (std::istream& instr, FString& s) //---------------------------------------------------------------------- std::wostream& operator << (std::wostream& outstr, const FString& s) { + const std::size_t width = std::size_t(outstr.width()); + if ( s.length > 0 ) + { outstr << s.string; + } + else if ( width > 0 ) + { + FString fill_str(width, outstr.fill()); + outstr << fill_str.string; + } return outstr; } diff --git a/src/fterm.cpp b/src/fterm.cpp index c29da34d..a6217394 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -835,8 +835,10 @@ int FTerm::closeConsole() if ( fd < 0 ) // console is already closed return 0; - if ( fsys ) - ret = fsys->close(fd); // close console + if ( ! fsys ) + getFSystem(); + + ret = fsys->close(fd); // close console data->setTTYFileDescriptor(-1); @@ -900,10 +902,10 @@ void FTerm::detectTermSize() do { - if ( fsys ) - ret = fsys->ioctl (FTermios::getStdOut(), TIOCGWINSZ, &win_size); - else - ret = -1; + if ( ! fsys ) + getFSystem(); + + ret = fsys->ioctl (FTermios::getStdOut(), TIOCGWINSZ, &win_size); } while (errno == EINTR); @@ -1199,12 +1201,18 @@ bool FTerm::scrollTermReverse() //---------------------------------------------------------------------- void FTerm::putstring (const char str[], int affcnt) { + if ( ! fsys ) + getFSystem(); + fsys->tputs (str, affcnt, FTerm::putchar_ASCII); } //---------------------------------------------------------------------- int FTerm::putchar_ASCII (int c) { + if ( ! fsys ) + getFSystem(); + if ( fsys->putchar(char(c)) == EOF ) return 0; else @@ -1214,6 +1222,9 @@ int FTerm::putchar_ASCII (int c) //---------------------------------------------------------------------- int FTerm::putchar_UTF8 (int c) { + if ( ! fsys ) + getFSystem(); + if ( c < 0x80 ) { // 1 Byte (7-bit): 0xxxxxxx @@ -1752,6 +1763,9 @@ void FTerm::init_term_encoding() int stdout_no = FTermios::getStdOut(); const char* termtype = data->getTermType(); + if ( ! fsys ) + getFSystem(); + if ( fsys->isTTY(stdout_no) && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") ) { @@ -2357,6 +2371,9 @@ void FTerm::initBaudRate() uInt baud = FTermios::getBaudRate(); data->setBaudrate(baud); + if ( ! fsys ) + getFSystem(); + if ( fsys->isTTY(stdout_no) ) opti_move->setBaudRate(int(baud)); } @@ -2501,10 +2518,9 @@ void FTerm::signal_handler (int signum) init_term_object->finish(); std::fflush (stderr); std::fflush (stdout); - std::fprintf ( stderr - , "\nProgram stopped: signal %d (%s)\n" - , signum - , strsignal(signum) ); + std::cerr << "\nProgram stopped: signal " + << signum + << " (" << strsignal(signum) << ")" << std::endl; std::terminate(); } } @@ -2537,9 +2553,9 @@ wchar_t cp437_to_unicode (uChar c) for (std::size_t i{0}; i <= fc::lastCP437Item; i++) { - if ( fc::cp437_to_ucs[i][CP437] == c ) // found + if ( fc::cp437_ucs[i][CP437] == c ) // found { - ucs = fc::cp437_to_ucs[i][UNICODE]; + ucs = fc::cp437_ucs[i][UNICODE]; break; } } @@ -2556,9 +2572,9 @@ uChar unicode_to_cp437 (wchar_t ucs) for (std::size_t i{0}; i <= fc::lastCP437Item; i++) { - if ( fc::cp437_to_ucs[i][UNICODE] == ucs ) // found + if ( fc::cp437_ucs[i][UNICODE] == ucs ) // found { - c = uChar(fc::cp437_to_ucs[i][CP437]); + c = uChar(fc::cp437_ucs[i][CP437]); break; } } diff --git a/src/ftermdetection.cpp b/src/ftermdetection.cpp index 32938be3..7f30ee71 100644 --- a/src/ftermdetection.cpp +++ b/src/ftermdetection.cpp @@ -546,10 +546,11 @@ const FString FTermDetection::getXTermColorName (FColor color) struct timeval tv{}; int stdin_no = FTermios::getStdIn(); - char temp[512]{}; - std::fprintf (stdout, OSC "4;%hu;?" BEL, color); // get color - std::fflush(stdout); + // get color + std::fprintf (stdout, OSC "4;%hu;?" BEL, color); + std::fflush (stdout); + char temp[512]{}; FD_ZERO(&ifds); FD_SET(stdin_no, &ifds); tv.tv_sec = 0; diff --git a/src/ftextview.cpp b/src/ftextview.cpp index 734f0c20..08e0ce3b 100644 --- a/src/ftextview.cpp +++ b/src/ftextview.cpp @@ -241,7 +241,7 @@ void FTextView::insert (const FString& str, int pos) hbar->setPageSize (int(maxLineWidth), int(getTextWidth())); hbar->calculateSliderValues(); - if ( isShown() && ! hbar->isShown() ) + if ( isShown() && isHorizontallyScrollable() ) hbar->show(); } } @@ -256,10 +256,10 @@ void FTextView::insert (const FString& str, int pos) vbar->setPageSize (int(getRows()), int(getTextHeight())); vbar->calculateSliderValues(); - if ( isShown() && ! vbar->isShown() && getRows() > getTextHeight() ) + if ( isShown() && ! vbar->isShown() && isVerticallyScrollable() ) vbar->show(); - if ( isShown() && vbar->isShown() && getRows() <= getTextHeight() ) + if ( isShown() && vbar->isShown() && ! isVerticallyScrollable() ) vbar->hide(); processChanged(); @@ -566,15 +566,15 @@ void FTextView::adjustSize() if ( isShown() ) { - if ( last_line < int(height) + nf_offset - 1 ) - vbar->hide(); - else - vbar->show(); - - if ( max_width < int(width) - nf_offset - 1 ) - hbar->hide(); - else + if ( isHorizontallyScrollable() ) hbar->show(); + else + hbar->hide(); + + if ( isVerticallyScrollable() ) + vbar->show(); + else + vbar->hide(); } } @@ -662,18 +662,7 @@ void FTextView::draw() if ( isMonochron() ) setReverse(false); - if ( ! isShown() ) // first drawing - { - vbar->show(); - hbar->show(); - } - - if ( vbar->isShown() ) - vbar->redraw(); - - if ( hbar->isShown() ) - hbar->redraw(); - + drawScrollbars(); drawText(); if ( hasFocus() && getStatusBar() ) @@ -693,6 +682,20 @@ void FTextView::draw() flush_out(); } +//---------------------------------------------------------------------- +void FTextView::drawScrollbars() +{ + if ( ! hbar->isShown() && isHorizontallyScrollable() ) + hbar->show(); + else + vbar->redraw(); + + if ( ! vbar->isShown() && isVerticallyScrollable() ) + vbar->show(); + else + hbar->redraw(); +} + //---------------------------------------------------------------------- void FTextView::drawText() { diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 60ad3a1e..342a8f77 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -860,11 +860,12 @@ FVTerm::covered_state FVTerm::isCovered ( const FPoint& pos if ( ! area ) return non_covered; - bool found( area == vdesktop ); auto is_covered = non_covered; if ( FWidget::getWindowList() && ! FWidget::getWindowList()->empty() ) { + bool found( area == vdesktop ); + for (auto& win_obj : *FWidget::getWindowList()) { auto win = win_obj->getVWin(); diff --git a/src/include/final/fcharmap.h b/src/include/final/fcharmap.h index df54c767..1ddb3266 100644 --- a/src/include/final/fcharmap.h +++ b/src/include/final/fcharmap.h @@ -42,7 +42,7 @@ extern const std::size_t lastCharItem; extern int vt100_key_to_utf8[][2]; extern const std::size_t lastKeyItem; -extern wchar_t cp437_to_ucs[][2]; +extern wchar_t cp437_ucs[][2]; extern const std::size_t lastCP437Item; extern wchar_t halfWidth_fullWidth[][2]; diff --git a/src/include/final/flistview.h b/src/include/final/flistview.h index 3a7eabb4..5997e3bc 100644 --- a/src/include/final/flistview.h +++ b/src/include/final/flistview.h @@ -358,6 +358,9 @@ class FListView : public FWidget void adjustSize() override; private: + // Constants + static constexpr std::size_t checkbox_space = 4; + // Typedef struct Header; // forward declaration typedef std::vector
headerItems; diff --git a/src/include/final/foptimove.h b/src/include/final/foptimove.h index fc1ac381..12fc322f 100644 --- a/src/include/final/foptimove.h +++ b/src/include/final/foptimove.h @@ -58,7 +58,6 @@ #include #include -#include // need for printf #include #include #include diff --git a/src/include/final/fstring.h b/src/include/final/fstring.h index a08c934d..a1769cb9 100644 --- a/src/include/final/fstring.h +++ b/src/include/final/fstring.h @@ -280,6 +280,8 @@ class FString std::size_t length{0}; std::size_t bufsize{0}; mutable char* c_string{nullptr}; + static wchar_t null_char; + static const wchar_t const_null_char; }; @@ -292,9 +294,12 @@ inline const char* FString::getClassName() template inline wchar_t& FString::operator [] (const IndexT pos) { - if ( isNegative(pos) || pos >= IndexT(length) ) + if ( isNegative(pos) || pos > IndexT(length) ) throw std::out_of_range(""); // Invalid index position + if ( std::size_t(pos) == length ) + return null_char; + return string[std::size_t(pos)]; } @@ -302,9 +307,12 @@ inline wchar_t& FString::operator [] (const IndexT pos) template inline const wchar_t& FString::operator [] (const IndexT pos) const { - if ( isNegative(pos) || pos >= IndexT(length) ) + if ( isNegative(pos) || pos > IndexT(length) ) throw std::out_of_range(""); // Invalid index position + if ( std::size_t(pos) == length ) + return const_null_char; + return string[std::size_t(pos)]; } @@ -407,17 +415,17 @@ template inline FString& FString::sprintf (const FString format, Args&&... args) { static constexpr int BUFSIZE = 4096; - wchar_t buffer[BUFSIZE]{}; + wchar_t buf[BUFSIZE]{}; - if ( ! format ) + if ( format.isEmpty() ) { clear(); return *this; } - std::swprintf ( buffer, BUFSIZE - , format.wc_str(), std::forward(args)... ); - _assign(buffer); + std::swprintf ( buf, BUFSIZE, format.wc_str() + , std::forward(args)... ); + _assign(buf); return *this; } diff --git a/src/include/final/fterm.h b/src/include/final/fterm.h index 14d07785..e5f35ad5 100644 --- a/src/include/final/fterm.h +++ b/src/include/final/fterm.h @@ -418,10 +418,18 @@ inline bool FTerm::unsetUTF8() template inline void FTerm::putstringf (const char format[], Args&&... args) { - char buf[512]{}; - char* str = buf; - std::snprintf (str, sizeof(buf), format, std::forward(args)...); - fsys->tputs (str, 1, FTerm::putchar_ASCII); + int size = std::snprintf ( nullptr, 0, format + , std::forward(args)... ) + 1; + + if ( size == -1 ) + return; + + if ( ! fsys ) + getFSystem(); + + std::vector buf(size); + std::snprintf (&buf[0], size, format, std::forward(args)...); + fsys->tputs (&buf[0], 1, FTerm::putchar_ASCII); } } // namespace finalcut diff --git a/src/include/final/ftermbuffer.h b/src/include/final/ftermbuffer.h index c1c3da75..59ef169b 100644 --- a/src/include/final/ftermbuffer.h +++ b/src/include/final/ftermbuffer.h @@ -208,15 +208,8 @@ inline void FTermBuffer::clear() template inline int FTermBuffer::writef (const FString format, Args&&... args) { - static constexpr int BUFSIZE = 4096; - wchar_t buffer[BUFSIZE]{}; - - if ( format.isEmpty() ) - return 0; - - std::swprintf ( buffer, BUFSIZE - , format.wc_str(), std::forward(args)... ); - FString str(buffer); + FString str{}; + str.sprintf (format, std::forward(args)...); return write(str); } diff --git a/src/include/final/ftextview.h b/src/include/final/ftextview.h index 3e571106..1b3fc90b 100644 --- a/src/include/final/ftextview.h +++ b/src/include/final/ftextview.h @@ -85,6 +85,13 @@ class FTextView : public FWidget // Disable assignment operator (=) FTextView& operator = (const FTextView&) = delete; + // Overloaded operators + FTextView& operator = (const FString&); + template + FTextView& operator << (const typeT&); + FTextView& operator << (fc::SpecialCharacter); + FTextView& operator << (const std::string&); + // Accessors const char* getClassName() const override; std::size_t getColumns() const; @@ -147,6 +154,7 @@ class FTextView : public FWidget , fc::orientation , FTextViewCallback ); void draw() override; + void drawScrollbars(); void drawText(); bool isPrintable (wchar_t); void processChanged(); @@ -167,6 +175,40 @@ class FTextView : public FWidget }; // FListBox inline functions +//---------------------------------------------------------------------- +FTextView& FTextView::operator = (const FString& s) +{ + setText(s); + return *this; +} + +//---------------------------------------------------------------------- +template +inline FTextView& FTextView::operator << (const typeT& s) +{ + std::wostringstream outstream; + outstream << s; + + if ( ! outstream.str().empty() ) + append (outstream.str()); + + return *this; +} + +//---------------------------------------------------------------------- +inline FTextView& FTextView::operator << (fc::SpecialCharacter c) +{ + append (static_cast(c)); // Required under Solaris + return *this; +} + +//---------------------------------------------------------------------- +inline FTextView& FTextView::operator << (const std::string& string) +{ + append (string); + return *this; +} + //---------------------------------------------------------------------- inline const char* FTextView::getClassName() const { return "FTextView"; } diff --git a/src/include/final/fvterm.h b/src/include/final/fvterm.h index ca8b9039..a00cb9a8 100644 --- a/src/include/final/fvterm.h +++ b/src/include/final/fvterm.h @@ -1047,15 +1047,8 @@ inline bool FVTerm::hasUTF8() template inline int FVTerm::printf (const FString format, Args&&... args) { - static constexpr int BUFSIZE = 4096; - wchar_t buffer[BUFSIZE]{}; - - if ( format.isEmpty() ) - return 0; - - std::swprintf ( buffer, BUFSIZE - , format.wc_str(), std::forward(args)... ); - FString str(buffer); + FString str{}; + str.sprintf (format, std::forward(args)...); return print(str); } diff --git a/test/fstring-test.cpp b/test/fstring-test.cpp index 57f61f86..ea669d02 100644 --- a/test/fstring-test.cpp +++ b/test/fstring-test.cpp @@ -558,6 +558,7 @@ void FStringTest::equalTest() constexpr wchar_t wch = L'a'; CPPUNIT_ASSERT ( one_char == wch ); CPPUNIT_ASSERT ( wch == one_char.wc_str()[0] ); + CPPUNIT_ASSERT ( L'\0' == one_char.wc_str()[1] ); // pos == size const finalcut::FString str(L"abc"); const finalcut::FString str2(L"abc"); @@ -875,14 +876,27 @@ void FStringTest::streamInsertionTest() out << lDouble(3.141592653589793238L); CPPUNIT_ASSERT ( out == L"3.14159265358979324" ); - out = "abc"; + out.clear(); std::ostringstream ostream; ostream << out; + CPPUNIT_ASSERT ( ostream.str() == "" ); + ostream << std::setfill('*') << std::setw(5) << out; + CPPUNIT_ASSERT ( ostream.str() == "*****" ); + out = "abc"; + ostream.str(""); + ostream << out; CPPUNIT_ASSERT ( ostream.str() == "abc" ); + out.clear(); std::wostringstream wostream; wostream << out; - CPPUNIT_ASSERT ( wostream.str() == L"abc" ); + CPPUNIT_ASSERT ( wostream.str() == L"" ); + wostream << std::setfill(L'+') << std::setw(7) << out; + CPPUNIT_ASSERT ( wostream.str() == L"+++++++" ); + out = L"def"; + wostream.str(L""); + wostream << out; + CPPUNIT_ASSERT ( wostream.str() == L"def" ); } //---------------------------------------------------------------------- @@ -957,12 +971,14 @@ void FStringTest::subscriptOperatorTest() CPPUNIT_ASSERT ( s[0] == L'\0' ); CPPUNIT_ASSERT ( s[1] == L'\0' ); CPPUNIT_ASSERT ( s[2] == L'\0' ); + CPPUNIT_ASSERT ( s[3] == L'\0' ); // pos == size s[0] = L'A'; s[1] = L'B'; s[2] = L'C'; CPPUNIT_ASSERT ( s[0] == L'A' ); CPPUNIT_ASSERT ( s[1] == L'B' ); CPPUNIT_ASSERT ( s[2] == L'C' ); + CPPUNIT_ASSERT ( s[3] == L'\0' ); // pos == size CPPUNIT_ASSERT ( s == L"ABC" ); } @@ -1202,7 +1218,7 @@ void FStringTest::exceptionTest() CPPUNIT_ASSERT_THROW ( finalcut::FString("abc").toULong() , std::invalid_argument ); - CPPUNIT_ASSERT_THROW ( finalcut::FString("abc")[3] + CPPUNIT_ASSERT_THROW ( finalcut::FString("abc")[4] , std::out_of_range ); CPPUNIT_ASSERT_THROW ( finalcut::FString("abc")[-1] diff --git a/test/ftermfreebsd-test.cpp b/test/ftermfreebsd-test.cpp index fa0b4bcd..b1860d1d 100644 --- a/test/ftermfreebsd-test.cpp +++ b/test/ftermfreebsd-test.cpp @@ -600,6 +600,7 @@ class ftermfreebsdTest : public CPPUNIT_NS::TestFixture, test::ConEmu // End of test suite definition CPPUNIT_TEST_SUITE_END(); + wchar_t charEncode (wchar_t); }; //---------------------------------------------------------------------- @@ -697,46 +698,60 @@ void ftermfreebsdTest::freebsdConsoleTest() freebsd.setCursorStyle(freebsd.getCursorStyle()); CPPUNIT_ASSERT ( freebsd.getCursorStyle() == finalcut::fc::blink_cursor ); - finalcut::fc::encoding enc = finalcut::fc::PC; - CPPUNIT_ASSERT ( finalcut::fc::character[2][enc] == 21 ); - CPPUNIT_ASSERT ( finalcut::fc::character[3][enc] == 8 ); - CPPUNIT_ASSERT ( finalcut::fc::character[4][enc] == 10 ); - CPPUNIT_ASSERT ( finalcut::fc::character[5][enc] == 19 ); - CPPUNIT_ASSERT ( finalcut::fc::character[6][enc] == 18 ); - CPPUNIT_ASSERT ( finalcut::fc::character[8][enc] == 22 ); - CPPUNIT_ASSERT ( finalcut::fc::character[9][enc] == 24 ); - CPPUNIT_ASSERT ( finalcut::fc::character[10][enc] == 25 ); - CPPUNIT_ASSERT ( finalcut::fc::character[11][enc] == 26 ); - CPPUNIT_ASSERT ( finalcut::fc::character[12][enc] == 27 ); - CPPUNIT_ASSERT ( finalcut::fc::character[23][enc] == 4 ); - CPPUNIT_ASSERT ( finalcut::fc::character[25][enc] == 4 ); - CPPUNIT_ASSERT ( finalcut::fc::character[26][enc] == 4 ); - CPPUNIT_ASSERT ( finalcut::fc::character[57][enc] == 16 ); - CPPUNIT_ASSERT ( finalcut::fc::character[58][enc] == 17 ); - CPPUNIT_ASSERT ( finalcut::fc::character[59][enc] == 16 ); - CPPUNIT_ASSERT ( finalcut::fc::character[60][enc] == 17 ); - CPPUNIT_ASSERT ( finalcut::fc::character[105][enc] == 4 ); + const auto c1 = finalcut::fc::Section; // § + const auto c2 = finalcut::fc::InverseBullet; // ◘ + const auto c3 = finalcut::fc::InverseWhiteCircle; // ◙ + const auto c4 = finalcut::fc::DoubleExclamationMark; // ‼ + const auto c5 = finalcut::fc::UpDownArrow; // ↕ + const auto c6 = finalcut::fc::BlackRectangle; // ▬ + const auto c7 = finalcut::fc::UpwardsArrow; // ↑ + const auto c8 = finalcut::fc::DownwardsArrow; // ↓ + const auto c9 = finalcut::fc::RightwardsArrow; // → + const auto c10 = finalcut::fc::LeftwardsArrow; // ← + const auto c11 = finalcut::fc::Bullet; // • + const auto c12 = finalcut::fc::BlackCircle; // ● + const auto c13 = finalcut::fc::BlackDiamondSuit; // ◆ + const auto c14 = finalcut::fc::BlackRightPointingTriangle; // ▶ + const auto c15 = finalcut::fc::BlackLeftPointingTriangle; // ◀ + const auto c16 = finalcut::fc::BlackRightPointingPointer; // ► + const auto c17 = finalcut::fc::BlackLeftPointingPointer; // ◄ + CPPUNIT_ASSERT ( charEncode(c1) == 21 ); // § + CPPUNIT_ASSERT ( charEncode(c2) == 8 ); // ◘ + CPPUNIT_ASSERT ( charEncode(c3) == 10 ); // ◙ + CPPUNIT_ASSERT ( charEncode(c4) == 19 ); // ‼ + CPPUNIT_ASSERT ( charEncode(c5) == 18 ); // ↕ + CPPUNIT_ASSERT ( charEncode(c6) == 22 ); // ▬ + CPPUNIT_ASSERT ( charEncode(c7) == 24 ); // ↑ + CPPUNIT_ASSERT ( charEncode(c8) == 25 ); // ↓ + CPPUNIT_ASSERT ( charEncode(c9) == 26 ); // → + CPPUNIT_ASSERT ( charEncode(c10) == 27 ); // ← + CPPUNIT_ASSERT ( charEncode(c11) == 4 ); // • + CPPUNIT_ASSERT ( charEncode(c12) == 4 ); // ● + CPPUNIT_ASSERT ( charEncode(c13) == 4 ); // ◆ + CPPUNIT_ASSERT ( charEncode(c14) == 16 ); // ▶ + CPPUNIT_ASSERT ( charEncode(c15) == 17 ); // ◀ + CPPUNIT_ASSERT ( charEncode(c16) == 16 ); // ► + CPPUNIT_ASSERT ( charEncode(c17) == 17 ); // ◄ freebsd.initCharMap(); - CPPUNIT_ASSERT ( finalcut::fc::character[2][enc] == 36 ); - CPPUNIT_ASSERT ( finalcut::fc::character[3][enc] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[4][enc] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[5][enc] == 33 ); - CPPUNIT_ASSERT ( finalcut::fc::character[6][enc] == 73 ); - CPPUNIT_ASSERT ( finalcut::fc::character[8][enc] == 95 ); - CPPUNIT_ASSERT ( finalcut::fc::character[9][enc] == 94 ); - CPPUNIT_ASSERT ( finalcut::fc::character[10][enc] == 118 ); - CPPUNIT_ASSERT ( finalcut::fc::character[11][enc] == 62 ); - CPPUNIT_ASSERT ( finalcut::fc::character[12][enc] == 60 ); - CPPUNIT_ASSERT ( finalcut::fc::character[23][enc] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[25][enc] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[26][enc] == 42 ); - CPPUNIT_ASSERT ( finalcut::fc::character[57][enc] == 62 ); - CPPUNIT_ASSERT ( finalcut::fc::character[58][enc] == 60 ); - CPPUNIT_ASSERT ( finalcut::fc::character[59][enc] == 62 ); - CPPUNIT_ASSERT ( finalcut::fc::character[60][enc] == 60 ); - CPPUNIT_ASSERT ( finalcut::fc::character[105][enc] == 42 ); + CPPUNIT_ASSERT ( charEncode(c1) == 36 ); // $ + CPPUNIT_ASSERT ( charEncode(c2) == 42 ); // * + CPPUNIT_ASSERT ( charEncode(c3) == 42 ); // * + CPPUNIT_ASSERT ( charEncode(c4) == 33 ); // ! + CPPUNIT_ASSERT ( charEncode(c5) == 73 ); // I + CPPUNIT_ASSERT ( charEncode(c6) == 95 ); // _ + CPPUNIT_ASSERT ( charEncode(c7) == 94 ); // ^ + CPPUNIT_ASSERT ( charEncode(c8) == 118 ); // v + CPPUNIT_ASSERT ( charEncode(c9) == 62 ); // > + CPPUNIT_ASSERT ( charEncode(c10) == 60 ); // < + CPPUNIT_ASSERT ( charEncode(c11) == 42 ); // * + CPPUNIT_ASSERT ( charEncode(c12) == 42 ); // * + CPPUNIT_ASSERT ( charEncode(c13) == 42 ); // * + CPPUNIT_ASSERT ( charEncode(c14) == 62 ); // > + CPPUNIT_ASSERT ( charEncode(c15) == 60 ); // < + CPPUNIT_ASSERT ( charEncode(c16) == 62 ); // > + CPPUNIT_ASSERT ( charEncode(c17) == 60 ); // < term_detection->detect(); @@ -798,6 +813,22 @@ void ftermfreebsdTest::freebsdConsoleTest() delete fsys; } +//---------------------------------------------------------------------- +wchar_t ftermfreebsdTest::charEncode (wchar_t c) +{ + wchar_t ch_enc{L'\0'}; + + for (std::size_t i{0}; i <= finalcut::fc::lastCharItem; i++) + { + if ( finalcut::fc::character[i][finalcut::fc::UTF8] == uInt(c) ) + { + ch_enc = wchar_t(finalcut::fc::character[i][finalcut::fc::PC]); + break; + } + } + + return ch_enc; +} // Put the test suite in the registry CPPUNIT_TEST_SUITE_REGISTRATION (ftermfreebsdTest);