diff --git a/ChangeLog b/ChangeLog index f90263c0..50387185 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2019-02-24 Markus Gans + * FLineEdit now has the ability to define a character input filter + via regular expression (regex) + * Now FLineEdit can define a maximum character length for the input + * The cursor position can now be set directly in FLineEdit + 2019-02-07 Markus Gans * Add a "dynamic layout" Chapter into the first steps document diff --git a/doc/first-steps.md b/doc/first-steps.md index 457d83a3..ffd34414 100644 --- a/doc/first-steps.md +++ b/doc/first-steps.md @@ -702,8 +702,8 @@ class dialogWidget : public FDialog { setText ("Dialog"); setResizeable(); - btn.setGeometry (FPoint(1, 1), FSize(12, 1), false); - line.setGeometry (FPoint(2, 3), FSize(12, 1), false); + button.setGeometry (FPoint(1, 1), FSize(12, 1), false); + input.setGeometry (FPoint(2, 3), FSize(12, 1), false); // Set dialog geometry and calling adjustSize() setGeometry (FPoint(25, 5), FSize(40, 12)); setMinimumSize (FSize(25, 9)); @@ -727,12 +727,12 @@ class dialogWidget : public FDialog void adjustWidgets() { - auto bx = int(getWidth() - btn.getWidth() - 3); + auto bx = int(getWidth() - button.getWidth() - 3); auto by = int(getHeight() - 4); - btn.setPos (FPoint(bx, by), false); - line.setWidth (getWidth() - 4); + button.setPos (FPoint(bx, by), false); + input.setWidth (getWidth() - 4); auto ly = int(getHeight() / 2) - 1; - line.setY (ly, false); + input.setY (ly, false); } virtual void adjustSize() override @@ -764,8 +764,8 @@ class dialogWidget : public FDialog << "top"; } - FLineEdit line{"Middle", this}; - FButton btn{"&Bottom", this}; + FLineEdit input{"Middle", this}; + FButton button{"&Bottom", this}; }; int main (int argc, char* argv[]) diff --git a/examples/termcap.cpp b/examples/termcap.cpp index 6f18cbf2..0df88474 100644 --- a/examples/termcap.cpp +++ b/examples/termcap.cpp @@ -3,7 +3,7 @@ * * * This file is part of the Final Cut widget toolkit * * * -* Copyright 2017-2018 Markus Gans * +* Copyright 2017-2019 Markus Gans * * * * The Final Cut is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * @@ -313,7 +313,7 @@ int main (int argc, char* argv[]) // Pointer to the global virtual terminal object terminal = static_cast(&TermApp); - finalcut::FTermcap::tcap_map* tcap = nullptr; + finalcut::FTermcap::tcap_map* tcap; tcap = finalcut::FTermcap::getTermcapMap(); std::cout << "--------\r\nFTermcap\r\n--------\r\n\n"; diff --git a/examples/ui.cpp b/examples/ui.cpp index d9751249..694bfdf1 100644 --- a/examples/ui.cpp +++ b/examples/ui.cpp @@ -269,7 +269,7 @@ class MyDialog : public finalcut::FDialog MyDialog& operator = (const MyDialog&) = delete; private: - // Method + // Methods void initMenu(); void initMenuCallbacks(); void initFileMenuCallbacks(); diff --git a/src/flineedit.cpp b/src/flineedit.cpp index 89fdd4f9..b60bb43a 100644 --- a/src/flineedit.cpp +++ b/src/flineedit.cpp @@ -20,6 +20,8 @@ * . * ***********************************************************************/ +#include + #include "final/fapplication.h" #include "final/flineedit.h" #include "final/fstatusbar.h" @@ -244,13 +246,41 @@ bool FLineEdit::setShadow (bool enable) //---------------------------------------------------------------------- void FLineEdit::setText (const FString& txt) { - text_offset = 0; - cursor_pos = 0; - if ( txt ) - text = txt; + { + if ( txt.getLength() > max_length ) + text = txt.left(max_length); + else + text = txt; + } else text = ""; + + keyEnd(); +} + +//---------------------------------------------------------------------- +void FLineEdit::setMaxLength (std::size_t max) +{ + max_length = max; + + if ( text.getLength() > max_length ) + text = text.left(max_length); + + keyEnd(); +} + +//---------------------------------------------------------------------- +void FLineEdit::setCursorPosition (std::size_t pos) +{ + cursor_pos = pos; + + if ( cursor_pos > text.getLength() ) + keyEnd(); + else if ( cursor_pos >= getWidth() - 1 ) + text_offset = text.getLength() - getWidth() + 2; + else + text_offset = 0; } //---------------------------------------------------------------------- @@ -766,6 +796,8 @@ inline void FLineEdit::keyEnd() if ( cursor_pos >= getWidth() - 1 ) text_offset = len - getWidth() + 2; + else + text_offset = 0; } //---------------------------------------------------------------------- @@ -792,11 +824,12 @@ inline void FLineEdit::keyBackspace() if ( text.getLength() > 0 && cursor_pos > 0 ) { text.remove(cursor_pos - 1, 1); - processChanged(); cursor_pos--; if ( text_offset > 0 ) text_offset--; + + processChanged(); } } @@ -820,41 +853,57 @@ inline void FLineEdit::keyEnter() //---------------------------------------------------------------------- inline bool FLineEdit::keyInput (FKey key) { + if ( text.getLength() >= max_length ) + { + beep(); + return true; + } + if ( key >= 0x20 && key <= 0x10fff ) { std::size_t len = text.getLength(); + wchar_t c = characterFilter(wchar_t(key)); - if ( cursor_pos == len ) - { - text += wchar_t(key); - processChanged(); - } + if ( c == L'\0' ) + return false; + else if ( cursor_pos == len ) + text += c; else if ( len > 0 ) { if ( insert_mode ) - text.insert(wchar_t(key), cursor_pos); + text.insert(c, cursor_pos); else - text.overwrite(wchar_t(key), cursor_pos); - - processChanged(); + text.overwrite(c, cursor_pos); } else - { - text = wchar_t(key); - processChanged(); - } + text = c; cursor_pos++; if ( cursor_pos >= getWidth() - 1 ) text_offset++; + processChanged(); return true; } else return false; } +//---------------------------------------------------------------------- +inline wchar_t FLineEdit::characterFilter (const wchar_t c) +{ + if ( input_filter.empty() ) + return c; + + wchar_t character[2]{c, L'\0'}; + + if ( regex_match(character, std::wregex(input_filter)) ) + return c; + else + return L'\0'; +} + //---------------------------------------------------------------------- void FLineEdit::processActivate() { diff --git a/src/flistview.cpp b/src/flistview.cpp index 149a05c9..c1946e3d 100644 --- a/src/flistview.cpp +++ b/src/flistview.cpp @@ -1611,10 +1611,7 @@ void FListView::drawListLine ( const FListViewItem* item { for (std::size_t col = 0; col < item->column_list.size(); ) { - static constexpr std::size_t leading_space = 1; - static constexpr std::size_t checkbox_space = 4; static constexpr std::size_t ellipsis_length = 2; - const auto& text = item->column_list[col]; std::size_t width = std::size_t(header[col].width); std::size_t txt_length = text.getLength(); @@ -1626,6 +1623,7 @@ void FListView::drawListLine ( const FListViewItem* item if ( tree_view && col == 1 ) { + static constexpr std::size_t checkbox_space = 4; width -= (indent + 1); if ( item->isCheckable() ) @@ -1639,6 +1637,7 @@ void FListView::drawListLine ( const FListViewItem* item if ( align_offset + txt_length <= width ) { // Insert text and trailing space + static constexpr std::size_t leading_space = 1; line += text.left(width); line += FString ( leading_space + width - align_offset - txt_length, L' '); diff --git a/src/fsize.cpp b/src/fsize.cpp index cb8189c8..fa99cb21 100644 --- a/src/fsize.cpp +++ b/src/fsize.cpp @@ -44,7 +44,7 @@ FSize& FSize::operator = (const FSize& s) //---------------------------------------------------------------------- FSize& FSize::operator += (const FSize& s) { - std::size_t max = std::numeric_limits::max(); + constexpr std::size_t max = std::numeric_limits::max(); width = ( width < max - s.width) ? width + s.width : max; height = ( height < max - s.height) ? height + s.height : max; return *this; diff --git a/src/ftermbuffer.cpp b/src/ftermbuffer.cpp index eed29505..b65b8fd4 100644 --- a/src/ftermbuffer.cpp +++ b/src/ftermbuffer.cpp @@ -96,18 +96,14 @@ int FTermBuffer::write (wchar_t c) //---------------------------------------------------------------------- void FTermBuffer::write (const FColorPair& pair) { - charData nc; // next character - nc = FVTerm::getAttribute(); - nc.fg_color = pair.fg_color; - nc.bg_color = pair.bg_color; + FVTerm::setColor(pair.fg_color, pair.bg_color); } // FTermBuffer non-member operators //---------------------------------------------------------------------- -std::vector& operator << \ - ( std::vector& termString - , const FTermBuffer& buf ) +FTermBuffer::charDataVector& operator << ( FTermBuffer::charDataVector& termString + , const FTermBuffer& buf ) { if ( ! buf.data.empty() ) termString.assign(buf.data.begin(), buf.data.end()); diff --git a/src/ftermlinux.cpp b/src/ftermlinux.cpp index d0781753..460e0d3a 100644 --- a/src/ftermlinux.cpp +++ b/src/ftermlinux.cpp @@ -504,7 +504,6 @@ int FTermLinux::getFramebuffer_bpp() //---------------------------------------------------------------------- bool FTermLinux::getScreenFont() { - static constexpr std::size_t data_size = 4 * 32 * 512; struct console_font_op font; int fd_tty = FTerm::getTTYFileDescriptor(); @@ -525,6 +524,7 @@ bool FTermLinux::getScreenFont() // initialize with 0 try { + static constexpr std::size_t data_size = 4 * 32 * 512; font.data = new uChar[data_size](); } catch (const std::bad_alloc& ex) diff --git a/src/fvterm.cpp b/src/fvterm.cpp index a700ebd6..d5436c18 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -26,6 +26,7 @@ #include "final/fapplication.h" #include "final/fterm.h" +#include "final/ftermbuffer.h" #include "final/fvterm.h" #include "final/fwidget.h" #include "final/fwindow.h" @@ -79,12 +80,18 @@ FVTerm::FVTerm (bool initialize, bool disable_alt_screen) FVTerm::~FVTerm() // destructor { if ( init_object == this ) - { finish(); - } } +// Overloaded operators +//---------------------------------------------------------------------- +FVTerm& FVTerm::operator << (const FTermBuffer& term_buffer) +{ + print (term_buffer); + return *this; +} + // public methods of FVTerm //---------------------------------------------------------------------- FPoint FVTerm::getPrintCursor() @@ -317,12 +324,7 @@ int FVTerm::print (const FString& s) auto area = getPrintArea(); if ( ! area ) - { - if ( vdesktop ) - area = vdesktop; - else - return -1; - } + return -1; return print (area, s); } @@ -357,6 +359,27 @@ int FVTerm::print (term_area* area, const FString& s) return 0; } +//---------------------------------------------------------------------- +int FVTerm::print (const FTermBuffer& term_buffer) +{ + if ( term_buffer.isEmpty() ) + return -1; + + auto area = getPrintArea(); + + if ( ! area ) + return -1; + + return print (area, term_buffer); +} + +//---------------------------------------------------------------------- +int FVTerm::print (term_area* area, const FTermBuffer& term_buffer) +{ + const auto& term_string = term_buffer.getBuffer(); + return print (area, term_string); +} + //---------------------------------------------------------------------- int FVTerm::print (const std::vector& term_string) { @@ -366,12 +389,7 @@ int FVTerm::print (const std::vector& term_string) auto area = getPrintArea(); if ( ! area ) - { - if ( vdesktop ) - area = vdesktop; - else - return -1; - } + return -1; return print (area, term_string); } @@ -440,12 +458,7 @@ int FVTerm::print (wchar_t c) auto area = getPrintArea(); if ( ! area ) - { - if ( vdesktop ) - area = vdesktop; - else - return -1; - } + return -1; return print (area, c); } @@ -474,12 +487,7 @@ int FVTerm::print (charData& term_char) auto area = getPrintArea(); if ( ! area ) - { - if ( vdesktop ) - area = vdesktop; - else - return -1; - } + return -1; return print (area, term_char); } diff --git a/src/include/final/flineedit.h b/src/include/final/flineedit.h index 63d3f556..fd58ffed 100644 --- a/src/include/final/flineedit.h +++ b/src/include/final/flineedit.h @@ -3,7 +3,7 @@ * * * This file is part of the Final Cut widget toolkit * * * -* Copyright 2012-2018 Markus Gans * +* Copyright 2012-2019 Markus Gans * * * * The Final Cut is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * @@ -105,10 +105,16 @@ class FLineEdit : public FWidget // Accessors virtual const char* getClassName() const override; FString getText() const; + std::size_t getMaxLength() const; + std::size_t getCursorPosition() const; int getLabelOrientation(); // Mutators void setText (const FString&); + void setInputFilter (const FString&); + void clearInputFilter(); + void setMaxLength (std::size_t); + void setCursorPosition (std::size_t); void setLabelText (const FString&); void setLabelOrientation(const label_o); virtual bool setEnable(bool) override; @@ -167,6 +173,7 @@ class FLineEdit : public FWidget void keyInsert(); void keyEnter(); bool keyInput (FKey); + wchar_t characterFilter (const wchar_t); void processActivate(); void processChanged(); @@ -175,12 +182,14 @@ class FLineEdit : public FWidget FString label_text{""}; FLabel* label{}; label_o label_orientation{FLineEdit::label_left}; + std::wstring input_filter{}; dragScroll drag_scroll{FLineEdit::noScroll}; bool scroll_timer{false}; int scroll_repeat{100}; bool insert_mode{true}; std::size_t cursor_pos{0}; std::size_t text_offset{0}; + std::size_t max_length{std::numeric_limits::max()}; }; #pragma pack(pop) @@ -194,10 +203,26 @@ inline const char* FLineEdit::getClassName() const inline FString FLineEdit::getText() const { return text; } +//---------------------------------------------------------------------- +inline std::size_t FLineEdit::getMaxLength() const +{ return max_length; } + +//---------------------------------------------------------------------- +inline std::size_t FLineEdit::getCursorPosition() const +{ return cursor_pos; } + //---------------------------------------------------------------------- inline int FLineEdit::getLabelOrientation() { return int(label_orientation); } +//---------------------------------------------------------------------- +inline void FLineEdit::setInputFilter (const FString& regex_string) +{ input_filter = regex_string.wc_str(); } + +//---------------------------------------------------------------------- +inline void FLineEdit::clearInputFilter() +{ input_filter.clear(); } + //---------------------------------------------------------------------- inline bool FLineEdit::setEnable() { return setEnable(true); } diff --git a/src/include/final/fsize.h b/src/include/final/fsize.h index c97150e1..1efd77e1 100644 --- a/src/include/final/fsize.h +++ b/src/include/final/fsize.h @@ -3,7 +3,7 @@ * * * This file is part of the Final Cut widget toolkit * * * -* Copyright 2014-2018 Markus Gans * +* Copyright 2014-2019 Markus Gans * * * * The Final Cut is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * @@ -141,7 +141,7 @@ inline bool operator > (const FSize& s1, const FSize& s2) //---------------------------------------------------------------------- inline FSize operator + (const FSize& s1, const FSize& s2) { - std::size_t max = std::numeric_limits::max(); + constexpr std::size_t max = std::numeric_limits::max(); std::size_t w = ( s1.width < max - s2.width) ? s1.width + s2.width : max; std::size_t h = ( s1.height < max - s2.height) ? s1.height + s2.height : max; return FSize(w, h); diff --git a/src/include/final/ftermbuffer.h b/src/include/final/ftermbuffer.h index 1db499bd..e2455838 100644 --- a/src/include/final/ftermbuffer.h +++ b/src/include/final/ftermbuffer.h @@ -57,6 +57,7 @@ class FTermBuffer public: // Typedef typedef FOptiAttr::charData charData; + typedef std::vector charDataVector; // Constructor FTermBuffer() = default; @@ -65,17 +66,20 @@ class FTermBuffer virtual ~FTermBuffer(); // Overloaded operators - template - FTermBuffer& operator << (const type&); + template + FTermBuffer& operator << (const typeT&); + FTermBuffer& operator << (const std::string&); + FTermBuffer& operator << (const std::wstring&); FTermBuffer& operator << (const FColorPair&); // Non-member operators - friend std::vector& operator << ( std::vector& - , const FTermBuffer& ); + friend charDataVector& operator << ( charDataVector& + , const FTermBuffer& ); // Accessors virtual const char* getClassName() const; std::size_t getLength() const; + const charDataVector& getBuffer() const; // Inquiry bool isEmpty() const; @@ -87,23 +91,38 @@ class FTermBuffer int write (wchar_t); void write (const FColorPair&); FTermBuffer& write (); - std::vector getBuffer(); private: - std::vector data{}; + charDataVector data{}; }; #pragma pack(pop) // FTermBuffer inline functions //---------------------------------------------------------------------- -template -inline FTermBuffer& FTermBuffer::operator << (const type& s) +template +inline FTermBuffer& FTermBuffer::operator << (const typeT& s) { - FString str(s); std::wostringstream outstream; - outstream << str; - write (outstream.str()); + outstream << s; + + if ( ! outstream.str().empty() ) + write (outstream.str()); + + return *this; +} + +//---------------------------------------------------------------------- +inline FTermBuffer& FTermBuffer::operator << (const std::string& string) +{ + write (string); + return *this; +} + +//---------------------------------------------------------------------- +inline FTermBuffer& FTermBuffer::operator << (const std::wstring& wstring) +{ + write (wstring); return *this; } @@ -122,6 +141,10 @@ inline const char* FTermBuffer::getClassName() const inline std::size_t FTermBuffer::getLength() const { return data.size(); } +//---------------------------------------------------------------------- +inline const FTermBuffer::charDataVector& FTermBuffer::getBuffer() const +{ return data; } + //---------------------------------------------------------------------- inline bool FTermBuffer::isEmpty() const { return data.empty(); } @@ -134,10 +157,6 @@ inline void FTermBuffer::clear() inline FTermBuffer& FTermBuffer::write() { return *this; } -//---------------------------------------------------------------------- -inline std::vector FTermBuffer::getBuffer() -{ return data; } - } // namespace finalcut #endif // FTERMBUFFER_H diff --git a/src/include/final/fvterm.h b/src/include/final/fvterm.h index 51547487..b4859773 100644 --- a/src/include/final/fvterm.h +++ b/src/include/final/fvterm.h @@ -70,8 +70,10 @@ namespace finalcut { // class forward declaration +class FTermBuffer; class FWidget; + //---------------------------------------------------------------------- // class FVTerm //---------------------------------------------------------------------- @@ -130,8 +132,10 @@ class FVTerm FVTerm& operator = (const FVTerm&) = delete; // Overloaded operators - template - FVTerm& operator << (const type&); + template + FVTerm& operator << (const typeT&); + FVTerm& operator << (const std::string&); + FVTerm& operator << (const FTermBuffer&); FVTerm& operator << (const std::vector&); FVTerm& operator << (const FPoint&); FVTerm& operator << (const FColorPair&); @@ -162,7 +166,7 @@ class FVTerm void showCursor(); void setPrintCursor (const FPoint&); FColor rgb2ColorIndex (uInt8, uInt8, uInt8); - void setColor (FColor, FColor); + static void setColor (FColor, FColor); static void setNormal(); static bool setBold (bool); @@ -291,6 +295,8 @@ class FVTerm int printf (const FString, ...); int print (const FString&); int print (term_area*, const FString&); + int print (const FTermBuffer&); + int print (term_area*, const FTermBuffer&); int print (const std::vector&); int print (term_area*, const std::vector&); int print (wchar_t); @@ -535,8 +541,8 @@ struct FVTerm::term_area // define virtual terminal character properties // FVTerm inline functions //---------------------------------------------------------------------- -template -inline FVTerm& FVTerm::operator << (const type& s) +template +inline FVTerm& FVTerm::operator << (const typeT& s) { std::wostringstream outstream; outstream << s; @@ -547,6 +553,13 @@ inline FVTerm& FVTerm::operator << (const type& s) return *this; } +//---------------------------------------------------------------------- +inline FVTerm& FVTerm::operator << (const std::string& string) +{ + print (string); + return *this; +} + //---------------------------------------------------------------------- inline FVTerm& FVTerm::operator << \ (const std::vector& termString)