Streaming into an FTextView() object

This commit is contained in:
Markus Gans 2019-09-29 22:28:58 +02:00
parent 8c67f64db4
commit 6b9336d6c1
29 changed files with 290 additions and 156 deletions

View File

@ -1,3 +1,10 @@
2019-09-29 Markus Gans <guru.mail@muenster.de>
* 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 <guru.mail@muenster.de> 2019-09-28 Markus Gans <guru.mail@muenster.de>
* Support for displaying full-width characters (2 columns wide) * Support for displaying full-width characters (2 columns wide)
on the terminal. This is particularly important for the correct on the terminal. This is particularly important for the correct

View File

@ -56,12 +56,12 @@ The Final Cut FProgressbar widget:
Scrollable text in the FTextView widget: Scrollable text in the FTextView widget:
![FTextView](doc/textview.png) ![FTextView](doc/textview.png)
The Mandelbrot set example: The Mandelbrot set example:
![Mandelbrot set](doc/Mandelbrot.png) ![Mandelbrot set](doc/Mandelbrot.png)
newfont newfont

View File

@ -1,4 +1,5 @@
examples/.libs/* usr/share/doc/libfinal-examples/examples doc/readme.txt usr/lib/libfinal/examples
examples/*.cpp usr/share/doc/libfinal-examples/examples examples/.libs/* usr/lib/libfinal/examples
examples/Makefile.clang usr/share/doc/libfinal-examples/examples examples/*.cpp usr/lib/libfinal/examples
examples/Makefile.gcc usr/share/doc/libfinal-examples/examples examples/Makefile.clang usr/lib/libfinal/examples
examples/Makefile.gcc usr/lib/libfinal/examples

View File

@ -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

1
debian/rules vendored
View File

@ -19,6 +19,7 @@ include /usr/share/dpkg/default.mk
# main packaging script based on dh7 syntax # main packaging script based on dh7 syntax
%: %:
sed -i 's/doc\///g' README.md
dh $@ --with autotools-dev dh $@ --with autotools-dev
# debmake generated override targets # debmake generated override targets

View File

@ -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 support for creating a text-based user interface. The library supports
the programmer to develop an application for the text console. It allows the programmer to develop an application for the text console. It allows
the simultaneous handling of multiple text windows on the screen. the simultaneous handling of multiple text windows on the screen.

View File

@ -898,9 +898,7 @@ lDouble& Calc::getValue()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void Calc::setDisplay (lDouble d) void Calc::setDisplay (lDouble d)
{ {
char buffer[33]{}; input.sprintf("%32.11Lg", d);
snprintf (buffer, sizeof(buffer), "%32.11Lg", d);
input = buffer;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@ -74,9 +74,9 @@ int main (int argc, char* argv[])
scroll_text.setGeometry (FPoint(2, 8), FSize(32, 3)); scroll_text.setGeometry (FPoint(2, 8), FSize(32, 3));
finalcut::FString text_line{"FINAL CUT supports " finalcut::FString text_line{"FINAL CUT supports "
"full-width characters."}; "full-width characters."};
scroll_text << full(text_line);
scroll_text.setStatusbarMessage ("You can scroll right and " scroll_text.setStatusbarMessage ("You can scroll right and "
"left with the arrow keys"); "left with the arrow keys");
scroll_text.append(full(text_line));
// Create a OK button // Create a OK button
finalcut::FButton btn("&", &dgl); finalcut::FButton btn("&", &dgl);

View File

@ -87,8 +87,7 @@ void term_boundaries (int& x, int& y)
void move (int xold, int yold, int xnew, int ynew) void move (int xold, int yold, int xnew, int ynew)
{ {
// prints the cursor move escape sequence // prints the cursor move escape sequence
std::string sequence{}; finalcut::FString buffer{}, sequence{}, from{}, to{}, byte{};
char from[26]{}, to[26]{}, byte[20]{};
const std::string ctrl_character[] = const std::string ctrl_character[] =
{ {
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "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(xold, yold);
term_boundaries(xnew, ynew); 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 // get the move string
char* buffer = finalcut::FTerm::moveCursorString (xold, yold, xnew, ynew); buffer = finalcut::FTerm::moveCursorString (xold, yold, xnew, ynew);
uInt len = uInt(std::strlen(buffer));
for (uInt i = 0; i < len; i++) for (auto&& ch : buffer)
{ {
char ch = buffer[i];
if ( ch < 0x21 ) if ( ch < 0x21 )
sequence += ctrl_character[uInt(ch)]; sequence += ctrl_character[std::size_t(ch)];
else else
sequence += ch; sequence += ch;
sequence += ' '; 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 ) if ( len <= 1 )
snprintf (byte, sizeof(byte), "%d byte ", len); byte.sprintf ("%d byte ", len);
else 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";
} }

View File

@ -425,7 +425,7 @@ void FApplication::cmd_options (const int& argc, char* argv[])
{C_STR("no-esc-for-alt-meta"), no_argument, 0, 0 }, {C_STR("no-esc-for-alt-meta"), no_argument, 0, 0 },
#endif #endif
{0, 0, 0, 0 } {nullptr, 0, nullptr, 0 }
}; };
opterr = 0; opterr = 0;

View File

@ -144,8 +144,7 @@ uInt character[][fc::NUM_OF_ENCODINGS] =
{0x1af4, 0, 0xf4, 0}, // ] - NF_rev_menu_button3 (2) {0x1af4, 0, 0xf4, 0}, // ] - NF_rev_menu_button3 (2)
{0x1af5, 0, 0xf5, 0}, // ] - NF_shadow_box_right (2) {0x1af5, 0, 0xf5, 0}, // ] - NF_shadow_box_right (2)
{0x1afb, 0, 0xfb, 0}, // ✓ - NF_check_mark (2) {0x1afb, 0, 0xfb, 0}, // ✓ - NF_check_mark (2)
{0x221a, 0, 0xfb, 'x'}, // √ - square root {0x221a, 0, 0xfb, 'x'} // √ - square root
{0x25cf, '`', 0x04, '*'} // ● - black circle
}; };
/* /*
@ -204,7 +203,7 @@ const std::size_t lastKeyItem = \
std::size_t((sizeof(vt100_key_to_utf8) / sizeof(vt100_key_to_utf8[0])) - 1); 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 {0x00, 0x0000}, // null
{0x01, 0x263a}, // white smiling face {0x01, 0x263a}, // white smiling face
@ -465,7 +464,7 @@ wchar_t cp437_to_ucs[][2] =
}; };
const std::size_t lastCP437Item = \ 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 // Based on http://www.unicode.org/charts/PDF/UFF00.pdf
wchar_t halfWidth_fullWidth[][2] = wchar_t halfWidth_fullWidth[][2] =

View File

@ -825,7 +825,7 @@ inline FLineEdit::offsetPair FLineEdit::endPosToOffset (std::size_t pos)
{ {
if ( char_width == 1 ) 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; fullwidth_char_offset = 1;
break; break;

View File

@ -1648,10 +1648,7 @@ void FListView::drawListLine ( const FListViewItem* item
width -= (indent + 1); width -= (indent + 1);
if ( item->isCheckable() ) if ( item->isCheckable() )
{
static constexpr std::size_t checkbox_space = 4;
width -= checkbox_space; width -= checkbox_space;
}
} }
// Insert alignment spaces // Insert alignment spaces
@ -1999,7 +1996,6 @@ void FListView::updateDrawing (bool draw_vbar, bool draw_hbar)
std::size_t FListView::determineLineWidth (FListViewItem* item) std::size_t FListView::determineLineWidth (FListViewItem* item)
{ {
static constexpr std::size_t padding_space = 1; 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 line_width = padding_space; // leading space
std::size_t column_idx{0}; std::size_t column_idx{0};
std::size_t entries = std::size_t(item->column_list.size()); 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() void FListView::mouseHeaderClicked()
{ {
int column{1}; int column{1};
int checkbox_offset = ( hasCheckableItems() ) ? 4 : 0; int checkbox_offset = ( hasCheckableItems() ) ? checkbox_space : 0;
int header_start = 2 + checkbox_offset; int header_start = 2 + checkbox_offset;
int header_pos = clicked_header_pos.getX() + xoffset; int header_pos = clicked_header_pos.getX() + xoffset;

View File

@ -534,7 +534,6 @@ inline void FMenuBar::drawItem (FMenuItem* menuitem, std::size_t& x)
if ( hotkeypos != NOT_SET ) if ( hotkeypos != NOT_SET )
{ {
txt_length--;
column_width--; column_width--;
to_char--; to_char--;
} }

View File

@ -30,6 +30,10 @@
namespace finalcut namespace finalcut
{ {
// static class attributes
wchar_t FString::null_char{L'\0'};
const wchar_t FString::const_null_char{L'\0'};
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// class FString // class FString
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -1710,8 +1714,17 @@ const FString operator + (const FString& s, const char c)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
std::ostream& operator << (std::ostream& outstr, const FString& s) std::ostream& operator << (std::ostream& outstr, const FString& s)
{ {
const std::size_t width = std::size_t(outstr.width());
if ( s.length > 0 ) 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; return outstr;
} }
@ -1735,8 +1748,17 @@ std::istream& operator >> (std::istream& instr, FString& s)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
std::wostream& operator << (std::wostream& outstr, const 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 ) if ( s.length > 0 )
{
outstr << s.string; outstr << s.string;
}
else if ( width > 0 )
{
FString fill_str(width, outstr.fill());
outstr << fill_str.string;
}
return outstr; return outstr;
} }

View File

@ -835,8 +835,10 @@ int FTerm::closeConsole()
if ( fd < 0 ) // console is already closed if ( fd < 0 ) // console is already closed
return 0; return 0;
if ( fsys ) if ( ! fsys )
ret = fsys->close(fd); // close console getFSystem();
ret = fsys->close(fd); // close console
data->setTTYFileDescriptor(-1); data->setTTYFileDescriptor(-1);
@ -900,10 +902,10 @@ void FTerm::detectTermSize()
do do
{ {
if ( fsys ) if ( ! fsys )
ret = fsys->ioctl (FTermios::getStdOut(), TIOCGWINSZ, &win_size); getFSystem();
else
ret = -1; ret = fsys->ioctl (FTermios::getStdOut(), TIOCGWINSZ, &win_size);
} }
while (errno == EINTR); while (errno == EINTR);
@ -1199,12 +1201,18 @@ bool FTerm::scrollTermReverse()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FTerm::putstring (const char str[], int affcnt) void FTerm::putstring (const char str[], int affcnt)
{ {
if ( ! fsys )
getFSystem();
fsys->tputs (str, affcnt, FTerm::putchar_ASCII); fsys->tputs (str, affcnt, FTerm::putchar_ASCII);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int FTerm::putchar_ASCII (int c) int FTerm::putchar_ASCII (int c)
{ {
if ( ! fsys )
getFSystem();
if ( fsys->putchar(char(c)) == EOF ) if ( fsys->putchar(char(c)) == EOF )
return 0; return 0;
else else
@ -1214,6 +1222,9 @@ int FTerm::putchar_ASCII (int c)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int FTerm::putchar_UTF8 (int c) int FTerm::putchar_UTF8 (int c)
{ {
if ( ! fsys )
getFSystem();
if ( c < 0x80 ) if ( c < 0x80 )
{ {
// 1 Byte (7-bit): 0xxxxxxx // 1 Byte (7-bit): 0xxxxxxx
@ -1752,6 +1763,9 @@ void FTerm::init_term_encoding()
int stdout_no = FTermios::getStdOut(); int stdout_no = FTermios::getStdOut();
const char* termtype = data->getTermType(); const char* termtype = data->getTermType();
if ( ! fsys )
getFSystem();
if ( fsys->isTTY(stdout_no) if ( fsys->isTTY(stdout_no)
&& ! std::strcmp(nl_langinfo(CODESET), "UTF-8") ) && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") )
{ {
@ -2357,6 +2371,9 @@ void FTerm::initBaudRate()
uInt baud = FTermios::getBaudRate(); uInt baud = FTermios::getBaudRate();
data->setBaudrate(baud); data->setBaudrate(baud);
if ( ! fsys )
getFSystem();
if ( fsys->isTTY(stdout_no) ) if ( fsys->isTTY(stdout_no) )
opti_move->setBaudRate(int(baud)); opti_move->setBaudRate(int(baud));
} }
@ -2501,10 +2518,9 @@ void FTerm::signal_handler (int signum)
init_term_object->finish(); init_term_object->finish();
std::fflush (stderr); std::fflush (stderr);
std::fflush (stdout); std::fflush (stdout);
std::fprintf ( stderr std::cerr << "\nProgram stopped: signal "
, "\nProgram stopped: signal %d (%s)\n" << signum
, signum << " (" << strsignal(signum) << ")" << std::endl;
, strsignal(signum) );
std::terminate(); std::terminate();
} }
} }
@ -2537,9 +2553,9 @@ wchar_t cp437_to_unicode (uChar c)
for (std::size_t i{0}; i <= fc::lastCP437Item; i++) 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; break;
} }
} }
@ -2556,9 +2572,9 @@ uChar unicode_to_cp437 (wchar_t ucs)
for (std::size_t i{0}; i <= fc::lastCP437Item; i++) 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; break;
} }
} }

View File

@ -546,10 +546,11 @@ const FString FTermDetection::getXTermColorName (FColor color)
struct timeval tv{}; struct timeval tv{};
int stdin_no = FTermios::getStdIn(); int stdin_no = FTermios::getStdIn();
char temp[512]{}; // get color
std::fprintf (stdout, OSC "4;%hu;?" BEL, color); // get color std::fprintf (stdout, OSC "4;%hu;?" BEL, color);
std::fflush(stdout); std::fflush (stdout);
char temp[512]{};
FD_ZERO(&ifds); FD_ZERO(&ifds);
FD_SET(stdin_no, &ifds); FD_SET(stdin_no, &ifds);
tv.tv_sec = 0; tv.tv_sec = 0;

View File

@ -241,7 +241,7 @@ void FTextView::insert (const FString& str, int pos)
hbar->setPageSize (int(maxLineWidth), int(getTextWidth())); hbar->setPageSize (int(maxLineWidth), int(getTextWidth()));
hbar->calculateSliderValues(); hbar->calculateSliderValues();
if ( isShown() && ! hbar->isShown() ) if ( isShown() && isHorizontallyScrollable() )
hbar->show(); hbar->show();
} }
} }
@ -256,10 +256,10 @@ void FTextView::insert (const FString& str, int pos)
vbar->setPageSize (int(getRows()), int(getTextHeight())); vbar->setPageSize (int(getRows()), int(getTextHeight()));
vbar->calculateSliderValues(); vbar->calculateSliderValues();
if ( isShown() && ! vbar->isShown() && getRows() > getTextHeight() ) if ( isShown() && ! vbar->isShown() && isVerticallyScrollable() )
vbar->show(); vbar->show();
if ( isShown() && vbar->isShown() && getRows() <= getTextHeight() ) if ( isShown() && vbar->isShown() && ! isVerticallyScrollable() )
vbar->hide(); vbar->hide();
processChanged(); processChanged();
@ -566,15 +566,15 @@ void FTextView::adjustSize()
if ( isShown() ) if ( isShown() )
{ {
if ( last_line < int(height) + nf_offset - 1 ) if ( isHorizontallyScrollable() )
vbar->hide();
else
vbar->show();
if ( max_width < int(width) - nf_offset - 1 )
hbar->hide();
else
hbar->show(); hbar->show();
else
hbar->hide();
if ( isVerticallyScrollable() )
vbar->show();
else
vbar->hide();
} }
} }
@ -662,18 +662,7 @@ void FTextView::draw()
if ( isMonochron() ) if ( isMonochron() )
setReverse(false); setReverse(false);
if ( ! isShown() ) // first drawing drawScrollbars();
{
vbar->show();
hbar->show();
}
if ( vbar->isShown() )
vbar->redraw();
if ( hbar->isShown() )
hbar->redraw();
drawText(); drawText();
if ( hasFocus() && getStatusBar() ) if ( hasFocus() && getStatusBar() )
@ -693,6 +682,20 @@ void FTextView::draw()
flush_out(); 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() void FTextView::drawText()
{ {

View File

@ -860,11 +860,12 @@ FVTerm::covered_state FVTerm::isCovered ( const FPoint& pos
if ( ! area ) if ( ! area )
return non_covered; return non_covered;
bool found( area == vdesktop );
auto is_covered = non_covered; auto is_covered = non_covered;
if ( FWidget::getWindowList() && ! FWidget::getWindowList()->empty() ) if ( FWidget::getWindowList() && ! FWidget::getWindowList()->empty() )
{ {
bool found( area == vdesktop );
for (auto& win_obj : *FWidget::getWindowList()) for (auto& win_obj : *FWidget::getWindowList())
{ {
auto win = win_obj->getVWin(); auto win = win_obj->getVWin();

View File

@ -42,7 +42,7 @@ extern const std::size_t lastCharItem;
extern int vt100_key_to_utf8[][2]; extern int vt100_key_to_utf8[][2];
extern const std::size_t lastKeyItem; 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 const std::size_t lastCP437Item;
extern wchar_t halfWidth_fullWidth[][2]; extern wchar_t halfWidth_fullWidth[][2];

View File

@ -358,6 +358,9 @@ class FListView : public FWidget
void adjustSize() override; void adjustSize() override;
private: private:
// Constants
static constexpr std::size_t checkbox_space = 4;
// Typedef // Typedef
struct Header; // forward declaration struct Header; // forward declaration
typedef std::vector<Header> headerItems; typedef std::vector<Header> headerItems;

View File

@ -58,7 +58,6 @@
#include <cctype> #include <cctype>
#include <climits> #include <climits>
#include <cstdio> // need for printf
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>

View File

@ -280,6 +280,8 @@ class FString
std::size_t length{0}; std::size_t length{0};
std::size_t bufsize{0}; std::size_t bufsize{0};
mutable char* c_string{nullptr}; 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 <typename IndexT> template <typename IndexT>
inline wchar_t& FString::operator [] (const IndexT pos) 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 throw std::out_of_range(""); // Invalid index position
if ( std::size_t(pos) == length )
return null_char;
return string[std::size_t(pos)]; return string[std::size_t(pos)];
} }
@ -302,9 +307,12 @@ inline wchar_t& FString::operator [] (const IndexT pos)
template <typename IndexT> template <typename IndexT>
inline const wchar_t& FString::operator [] (const IndexT pos) const 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 throw std::out_of_range(""); // Invalid index position
if ( std::size_t(pos) == length )
return const_null_char;
return string[std::size_t(pos)]; return string[std::size_t(pos)];
} }
@ -407,17 +415,17 @@ template<typename... Args>
inline FString& FString::sprintf (const FString format, Args&&... args) inline FString& FString::sprintf (const FString format, Args&&... args)
{ {
static constexpr int BUFSIZE = 4096; static constexpr int BUFSIZE = 4096;
wchar_t buffer[BUFSIZE]{}; wchar_t buf[BUFSIZE]{};
if ( ! format ) if ( format.isEmpty() )
{ {
clear(); clear();
return *this; return *this;
} }
std::swprintf ( buffer, BUFSIZE std::swprintf ( buf, BUFSIZE, format.wc_str()
, format.wc_str(), std::forward<Args>(args)... ); , std::forward<Args>(args)... );
_assign(buffer); _assign(buf);
return *this; return *this;
} }

View File

@ -418,10 +418,18 @@ inline bool FTerm::unsetUTF8()
template<typename... Args> template<typename... Args>
inline void FTerm::putstringf (const char format[], Args&&... args) inline void FTerm::putstringf (const char format[], Args&&... args)
{ {
char buf[512]{}; int size = std::snprintf ( nullptr, 0, format
char* str = buf; , std::forward<Args>(args)... ) + 1;
std::snprintf (str, sizeof(buf), format, std::forward<Args>(args)...);
fsys->tputs (str, 1, FTerm::putchar_ASCII); if ( size == -1 )
return;
if ( ! fsys )
getFSystem();
std::vector<char> buf(size);
std::snprintf (&buf[0], size, format, std::forward<Args>(args)...);
fsys->tputs (&buf[0], 1, FTerm::putchar_ASCII);
} }
} // namespace finalcut } // namespace finalcut

View File

@ -208,15 +208,8 @@ inline void FTermBuffer::clear()
template<typename... Args> template<typename... Args>
inline int FTermBuffer::writef (const FString format, Args&&... args) inline int FTermBuffer::writef (const FString format, Args&&... args)
{ {
static constexpr int BUFSIZE = 4096; FString str{};
wchar_t buffer[BUFSIZE]{}; str.sprintf (format, std::forward<Args>(args)...);
if ( format.isEmpty() )
return 0;
std::swprintf ( buffer, BUFSIZE
, format.wc_str(), std::forward<Args>(args)... );
FString str(buffer);
return write(str); return write(str);
} }

View File

@ -85,6 +85,13 @@ class FTextView : public FWidget
// Disable assignment operator (=) // Disable assignment operator (=)
FTextView& operator = (const FTextView&) = delete; FTextView& operator = (const FTextView&) = delete;
// Overloaded operators
FTextView& operator = (const FString&);
template <typename typeT>
FTextView& operator << (const typeT&);
FTextView& operator << (fc::SpecialCharacter);
FTextView& operator << (const std::string&);
// Accessors // Accessors
const char* getClassName() const override; const char* getClassName() const override;
std::size_t getColumns() const; std::size_t getColumns() const;
@ -147,6 +154,7 @@ class FTextView : public FWidget
, fc::orientation , fc::orientation
, FTextViewCallback ); , FTextViewCallback );
void draw() override; void draw() override;
void drawScrollbars();
void drawText(); void drawText();
bool isPrintable (wchar_t); bool isPrintable (wchar_t);
void processChanged(); void processChanged();
@ -167,6 +175,40 @@ class FTextView : public FWidget
}; };
// FListBox inline functions // FListBox inline functions
//----------------------------------------------------------------------
FTextView& FTextView::operator = (const FString& s)
{
setText(s);
return *this;
}
//----------------------------------------------------------------------
template <typename typeT>
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<wchar_t>(c)); // Required under Solaris
return *this;
}
//----------------------------------------------------------------------
inline FTextView& FTextView::operator << (const std::string& string)
{
append (string);
return *this;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
inline const char* FTextView::getClassName() const inline const char* FTextView::getClassName() const
{ return "FTextView"; } { return "FTextView"; }

View File

@ -1047,15 +1047,8 @@ inline bool FVTerm::hasUTF8()
template<typename... Args> template<typename... Args>
inline int FVTerm::printf (const FString format, Args&&... args) inline int FVTerm::printf (const FString format, Args&&... args)
{ {
static constexpr int BUFSIZE = 4096; FString str{};
wchar_t buffer[BUFSIZE]{}; str.sprintf (format, std::forward<Args>(args)...);
if ( format.isEmpty() )
return 0;
std::swprintf ( buffer, BUFSIZE
, format.wc_str(), std::forward<Args>(args)... );
FString str(buffer);
return print(str); return print(str);
} }

View File

@ -558,6 +558,7 @@ void FStringTest::equalTest()
constexpr wchar_t wch = L'a'; constexpr wchar_t wch = L'a';
CPPUNIT_ASSERT ( one_char == wch ); CPPUNIT_ASSERT ( one_char == wch );
CPPUNIT_ASSERT ( wch == one_char.wc_str()[0] ); 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 str(L"abc");
const finalcut::FString str2(L"abc"); const finalcut::FString str2(L"abc");
@ -875,14 +876,27 @@ void FStringTest::streamInsertionTest()
out << lDouble(3.141592653589793238L); out << lDouble(3.141592653589793238L);
CPPUNIT_ASSERT ( out == L"3.14159265358979324" ); CPPUNIT_ASSERT ( out == L"3.14159265358979324" );
out = "abc"; out.clear();
std::ostringstream ostream; std::ostringstream ostream;
ostream << out; 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" ); CPPUNIT_ASSERT ( ostream.str() == "abc" );
out.clear();
std::wostringstream wostream; std::wostringstream wostream;
wostream << out; 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[0] == L'\0' );
CPPUNIT_ASSERT ( s[1] == L'\0' ); CPPUNIT_ASSERT ( s[1] == L'\0' );
CPPUNIT_ASSERT ( s[2] == L'\0' ); CPPUNIT_ASSERT ( s[2] == L'\0' );
CPPUNIT_ASSERT ( s[3] == L'\0' ); // pos == size
s[0] = L'A'; s[0] = L'A';
s[1] = L'B'; s[1] = L'B';
s[2] = L'C'; s[2] = L'C';
CPPUNIT_ASSERT ( s[0] == L'A' ); CPPUNIT_ASSERT ( s[0] == L'A' );
CPPUNIT_ASSERT ( s[1] == L'B' ); CPPUNIT_ASSERT ( s[1] == L'B' );
CPPUNIT_ASSERT ( s[2] == L'C' ); CPPUNIT_ASSERT ( s[2] == L'C' );
CPPUNIT_ASSERT ( s[3] == L'\0' ); // pos == size
CPPUNIT_ASSERT ( s == L"ABC" ); CPPUNIT_ASSERT ( s == L"ABC" );
} }
@ -1202,7 +1218,7 @@ void FStringTest::exceptionTest()
CPPUNIT_ASSERT_THROW ( finalcut::FString("abc").toULong() CPPUNIT_ASSERT_THROW ( finalcut::FString("abc").toULong()
, std::invalid_argument ); , std::invalid_argument );
CPPUNIT_ASSERT_THROW ( finalcut::FString("abc")[3] CPPUNIT_ASSERT_THROW ( finalcut::FString("abc")[4]
, std::out_of_range ); , std::out_of_range );
CPPUNIT_ASSERT_THROW ( finalcut::FString("abc")[-1] CPPUNIT_ASSERT_THROW ( finalcut::FString("abc")[-1]

View File

@ -600,6 +600,7 @@ class ftermfreebsdTest : public CPPUNIT_NS::TestFixture, test::ConEmu
// End of test suite definition // End of test suite definition
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
wchar_t charEncode (wchar_t);
}; };
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -697,46 +698,60 @@ void ftermfreebsdTest::freebsdConsoleTest()
freebsd.setCursorStyle(freebsd.getCursorStyle()); freebsd.setCursorStyle(freebsd.getCursorStyle());
CPPUNIT_ASSERT ( freebsd.getCursorStyle() == finalcut::fc::blink_cursor ); CPPUNIT_ASSERT ( freebsd.getCursorStyle() == finalcut::fc::blink_cursor );
finalcut::fc::encoding enc = finalcut::fc::PC; const auto c1 = finalcut::fc::Section; // §
CPPUNIT_ASSERT ( finalcut::fc::character[2][enc] == 21 ); const auto c2 = finalcut::fc::InverseBullet; // ◘
CPPUNIT_ASSERT ( finalcut::fc::character[3][enc] == 8 ); const auto c3 = finalcut::fc::InverseWhiteCircle; // ◙
CPPUNIT_ASSERT ( finalcut::fc::character[4][enc] == 10 ); const auto c4 = finalcut::fc::DoubleExclamationMark; // ‼
CPPUNIT_ASSERT ( finalcut::fc::character[5][enc] == 19 ); const auto c5 = finalcut::fc::UpDownArrow; // ↕
CPPUNIT_ASSERT ( finalcut::fc::character[6][enc] == 18 ); const auto c6 = finalcut::fc::BlackRectangle; // ▬
CPPUNIT_ASSERT ( finalcut::fc::character[8][enc] == 22 ); const auto c7 = finalcut::fc::UpwardsArrow; // ↑
CPPUNIT_ASSERT ( finalcut::fc::character[9][enc] == 24 ); const auto c8 = finalcut::fc::DownwardsArrow; // ↓
CPPUNIT_ASSERT ( finalcut::fc::character[10][enc] == 25 ); const auto c9 = finalcut::fc::RightwardsArrow; // →
CPPUNIT_ASSERT ( finalcut::fc::character[11][enc] == 26 ); const auto c10 = finalcut::fc::LeftwardsArrow; // ←
CPPUNIT_ASSERT ( finalcut::fc::character[12][enc] == 27 ); const auto c11 = finalcut::fc::Bullet; // •
CPPUNIT_ASSERT ( finalcut::fc::character[23][enc] == 4 ); const auto c12 = finalcut::fc::BlackCircle; // ●
CPPUNIT_ASSERT ( finalcut::fc::character[25][enc] == 4 ); const auto c13 = finalcut::fc::BlackDiamondSuit; // ◆
CPPUNIT_ASSERT ( finalcut::fc::character[26][enc] == 4 ); const auto c14 = finalcut::fc::BlackRightPointingTriangle; // ▶
CPPUNIT_ASSERT ( finalcut::fc::character[57][enc] == 16 ); const auto c15 = finalcut::fc::BlackLeftPointingTriangle; // ◀
CPPUNIT_ASSERT ( finalcut::fc::character[58][enc] == 17 ); const auto c16 = finalcut::fc::BlackRightPointingPointer; // ►
CPPUNIT_ASSERT ( finalcut::fc::character[59][enc] == 16 ); const auto c17 = finalcut::fc::BlackLeftPointingPointer; // ◄
CPPUNIT_ASSERT ( finalcut::fc::character[60][enc] == 17 ); CPPUNIT_ASSERT ( charEncode(c1) == 21 ); // §
CPPUNIT_ASSERT ( finalcut::fc::character[105][enc] == 4 ); 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(); freebsd.initCharMap();
CPPUNIT_ASSERT ( finalcut::fc::character[2][enc] == 36 ); CPPUNIT_ASSERT ( charEncode(c1) == 36 ); // $
CPPUNIT_ASSERT ( finalcut::fc::character[3][enc] == 42 ); CPPUNIT_ASSERT ( charEncode(c2) == 42 ); // *
CPPUNIT_ASSERT ( finalcut::fc::character[4][enc] == 42 ); CPPUNIT_ASSERT ( charEncode(c3) == 42 ); // *
CPPUNIT_ASSERT ( finalcut::fc::character[5][enc] == 33 ); CPPUNIT_ASSERT ( charEncode(c4) == 33 ); // !
CPPUNIT_ASSERT ( finalcut::fc::character[6][enc] == 73 ); CPPUNIT_ASSERT ( charEncode(c5) == 73 ); // I
CPPUNIT_ASSERT ( finalcut::fc::character[8][enc] == 95 ); CPPUNIT_ASSERT ( charEncode(c6) == 95 ); // _
CPPUNIT_ASSERT ( finalcut::fc::character[9][enc] == 94 ); CPPUNIT_ASSERT ( charEncode(c7) == 94 ); // ^
CPPUNIT_ASSERT ( finalcut::fc::character[10][enc] == 118 ); CPPUNIT_ASSERT ( charEncode(c8) == 118 ); // v
CPPUNIT_ASSERT ( finalcut::fc::character[11][enc] == 62 ); CPPUNIT_ASSERT ( charEncode(c9) == 62 ); // >
CPPUNIT_ASSERT ( finalcut::fc::character[12][enc] == 60 ); CPPUNIT_ASSERT ( charEncode(c10) == 60 ); // <
CPPUNIT_ASSERT ( finalcut::fc::character[23][enc] == 42 ); CPPUNIT_ASSERT ( charEncode(c11) == 42 ); // *
CPPUNIT_ASSERT ( finalcut::fc::character[25][enc] == 42 ); CPPUNIT_ASSERT ( charEncode(c12) == 42 ); // *
CPPUNIT_ASSERT ( finalcut::fc::character[26][enc] == 42 ); CPPUNIT_ASSERT ( charEncode(c13) == 42 ); // *
CPPUNIT_ASSERT ( finalcut::fc::character[57][enc] == 62 ); CPPUNIT_ASSERT ( charEncode(c14) == 62 ); // >
CPPUNIT_ASSERT ( finalcut::fc::character[58][enc] == 60 ); CPPUNIT_ASSERT ( charEncode(c15) == 60 ); // <
CPPUNIT_ASSERT ( finalcut::fc::character[59][enc] == 62 ); CPPUNIT_ASSERT ( charEncode(c16) == 62 ); // >
CPPUNIT_ASSERT ( finalcut::fc::character[60][enc] == 60 ); CPPUNIT_ASSERT ( charEncode(c17) == 60 ); // <
CPPUNIT_ASSERT ( finalcut::fc::character[105][enc] == 42 );
term_detection->detect(); term_detection->detect();
@ -798,6 +813,22 @@ void ftermfreebsdTest::freebsdConsoleTest()
delete fsys; 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 // Put the test suite in the registry
CPPUNIT_TEST_SUITE_REGISTRATION (ftermfreebsdTest); CPPUNIT_TEST_SUITE_REGISTRATION (ftermfreebsdTest);