diff --git a/module-apps/application-notes/windows/NotesEditWindow.cpp b/module-apps/application-notes/windows/NotesEditWindow.cpp index d9d05fb87..3d28a5b69 100644 --- a/module-apps/application-notes/windows/NotesEditWindow.cpp +++ b/module-apps/application-notes/windows/NotesEditWindow.cpp @@ -48,14 +48,17 @@ void NotesEditWindow::buildInterface() { title->setBorderColor( gui::ColorNoColor ); title->setFont("gt_pressura_bold_24"); title->setText("New Note"); - title->setAlignement( gui::Alignment(gui::Alignment::ALIGN_HORIZONTAL_RIGHT, gui::Alignment::ALIGN_VERTICAL_BOTTOM)); + title->setAlignement( gui::Alignment(gui::Alignment::ALIGN_HORIZONTAL_CENTER, gui::Alignment::ALIGN_VERTICAL_BOTTOM)); text = new gui::Text( this, 11, 150, 480-22, 400 ); text->setFont("gt_pressura_bold_24"); + text->setRadius(5); + text->setMargins( gui::Margins(10, 10, 10, 10)); topBar->setActive(TopBar::Elements::TIME, true ); } + void NotesEditWindow::destroyInterface() { AppWindow::destroyInterface(); children.clear(); @@ -66,6 +69,7 @@ NotesEditWindow::~NotesEditWindow() { } void NotesEditWindow::onBeforeShow( ShowMode mode, uint32_t command, SwitchData* data ) { + setFocusItem( text ); LOG_INFO("SETTING TEXT"); text->setText("Very long test line ABCDEFGHIJKLMNOPQRST123456789\nabcdefghijklmnopqrs 123456789 ABCDEFGHIJKLMONPQRSTUW 12345\n test\nnew line\n\n\n12345"); } diff --git a/module-gui/gui/core/Font.cpp b/module-gui/gui/core/Font.cpp index 5f0461265..2900787c1 100644 --- a/module-gui/gui/core/Font.cpp +++ b/module-gui/gui/core/Font.cpp @@ -300,6 +300,10 @@ uint32_t Font::getPixelWidth( const UTF8& str, const uint32_t start, const uint3 return stringPixelWidth; } +uint32_t Font::getPixelWidth( const UTF8& str ) { + return getPixelWidth( str, 0, str.length() ); +} + uint32_t Font::getCharPixelWidth( uint32_t charCode ) { FontGlyph* glyph = glyphs.find(charCode)->second; diff --git a/module-gui/gui/core/Font.hpp b/module-gui/gui/core/Font.hpp index aa63cad99..dd0ac6377 100644 --- a/module-gui/gui/core/Font.hpp +++ b/module-gui/gui/core/Font.hpp @@ -128,7 +128,17 @@ public: * @return Number of pixels in width occupied by selected part of the text. */ uint32_t getPixelWidth( const UTF8& str, const uint32_t start, const uint32_t count ); + /** + * @brief Calculates how many pixels will occupy string. + * @param str String used as a source of text. + * @return Number of pixels in width occupied by string. + */ + uint32_t getPixelWidth( const UTF8& str ); uint32_t getCharPixelWidth( uint32_t charCode ); + + const std::string getName() { + return info.face; + } }; class FontManager { diff --git a/module-gui/gui/widgets/Text.cpp b/module-gui/gui/widgets/Text.cpp index f7d9d9945..51fd8f010 100644 --- a/module-gui/gui/widgets/Text.cpp +++ b/module-gui/gui/widgets/Text.cpp @@ -36,6 +36,10 @@ Text::Text() : //insert first empty text line textLines.push_back( new TextLine( UTF8(""), 0, 0, LineEndType::EOT, 0 ) ); + firstLine = textLines.begin(); + lastLine = textLines.begin(); + setBorderColor( gui::ColorFullBlack ); + setEdges(RectangleEdgeFlags::GUI_RECT_ALL_EDGES); } Text::Text( Item* parent, const uint32_t& x, const uint32_t& y, const uint32_t& w, const uint32_t& h, @@ -51,6 +55,10 @@ Text::Text( Item* parent, const uint32_t& x, const uint32_t& y, const uint32_t& //insert first empty text line textLines.push_back( new TextLine( UTF8(""), 0, 0, LineEndType::EOT, 0 ) ); + firstLine = textLines.begin(); + lastLine = textLines.begin(); + setBorderColor( gui::ColorFullBlack ); + setEdges(RectangleEdgeFlags::GUI_RECT_ALL_EDGES); } Text::~Text() { @@ -67,15 +75,27 @@ void Text::setCursorWidth( uint32_t w ) { void Text::setText( const UTF8& text ) { clear(); + //erase default empty line + delete textLines.front(); + textLines.pop_front(); + textLines.clear(); + //split and add new lines splitTextToLines(text); + recalculateDrawParams(); } void Text::clear(){ //if there are text lines erase them. if( !textLines.empty() ) { - while( !textLines.empty() ) + while( !textLines.empty() ) { delete textLines.front(); textLines.pop_front(); + } } + textLines.clear(); + //insert first empty text line + textLines.push_back( new TextLine( UTF8(""), 0, 0, LineEndType::EOT, 0 ) ); + firstLine = textLines.begin(); + lastLine = textLines.begin(); } UTF8 Text::getText() { @@ -92,6 +112,7 @@ void Text::setFont( const UTF8& fontName) { } else { LOG_ERROR("Font not found"); } + recalculateDrawParams(); } void Text::splitTextToLines( const UTF8& text) { @@ -103,13 +124,15 @@ void Text::splitTextToLines( const UTF8& text) { uint32_t index = 0; uint32_t totalLength = text.length(); + uint32_t availableSpace = getAvailableHPixelSpace(); + while( index < totalLength ) { UTF8 textCopy = text.substr(index,totalLength-index); //find how many character fit in the widget's width //this doesnt include any line breaking conditinos like enter or space because line is too long uint32_t spaceConsumed = 0; - uint32_t charCount = font->getCharCountInSpace( textCopy, widgetArea.w, spaceConsumed ); + uint32_t charCount = font->getCharCountInSpace( textCopy, availableSpace, spaceConsumed ); UTF8 tmpText = textCopy.substr( 0, charCount ); //some default values @@ -185,24 +208,29 @@ void Text::splitTextToLines( const UTF8& text) { } } } + + firstLine = textLines.begin(); + lastLine = textLines.begin(); // for( TextLine* tl : textLines ) // LOG_INFO("Text Input Line: [%s]", tl->text.c_str()); } -void Text::reworkLines( TextLine* textLine ) { +void Text::reworkLines( std::list::iterator it ) { } std::list Text::buildDrawList() { - return Item::buildDrawList(); + return Rect::buildDrawList(); } void Text::setPosition( const short& x, const short& y ) { - + Rect::setPosition(x, y); + recalculateDrawParams(); } void Text::setSize( const short& w, const short& h ) { - + Rect::setSize( w, h ); + recalculateDrawParams(); } bool Text::onInput( const InputEvent& inputEvent ) { @@ -219,10 +247,10 @@ bool Text::onInput( const InputEvent& inputEvent ) { } //backspace handling else if( inputEvent.keyChar == 0x08 ) { - handleBackspace(); + return handleBackspace(); } else { //normal char -> add and check pixel width - handleChar( inputEvent ); + return handleChar( inputEvent ); } return false; @@ -323,14 +351,35 @@ bool Text::handleChar( const InputEvent& inputEvent ) { TextLine* currentTextLine = getCursorTextLine(); //calculate width of the character that is going to be inserted - font->getCharPixelWidth( inputEvent.keyChar ); + uint32_t charWidth = font->getCharPixelWidth( inputEvent.keyChar ); //insert character into string in currently selected line -// currentTextLine->text. + if( currentTextLine->text.insertCode( inputEvent.keyChar, cursorColumn ) == false ) + return false; + //if sum of the old string and width of the new character are greater than available space run lines rework procedure + uint32_t linesCount = textLines.size(); + uint32_t availableSpace = getAvailableHPixelSpace(); + uint32_t currentWidth = currentTextLine->pixelLength; + if( currentWidth + charWidth > availableSpace ) { + auto it = firstLine; + std::advance(it, cursorRow ); + reworkLines( it ); + + //change cursor position + } + //no line splitting, update pixel width and proceed + else { + currentTextLine->pixelLength = font->getPixelWidth( currentTextLine->text ); + ++cursorColumn; + } //if number of text lines have increased, text widget is multi-line and expandable change widgets space + if( linesCount != textLines.size()) { + } + + recalculateDrawParams(); //calculate new position of the cursor return true; @@ -343,4 +392,58 @@ Text::TextLine* Text::getCursorTextLine() { return *it; } +void Text::recalculateDrawParams() { + + //calculate number of lines for displaying text + int32_t h = widgetArea.h - margins.top - margins.bottom - 2*radius; + if( h < 0 ) + h = 0; + + //remove all old labels + for( uint32_t i=0; iinfo.line_height; + rowCount = (rowCount == 0)?1:rowCount; + + if( textType == TextType::SINGLE_LINE ) { + rowCount = 1; + } + + //if there is not enough space for single line start from 0 and ignore vertical margins + uint32_t startY = ( h < font->info.line_height )?0:margins.top; + + //create labels to display text. There will be always at least one. + for( uint32_t i=0; iinfo.line_height ); + label->setFilled( false ); + label->setFont( font-> getName() ); + label->setAlignement( gui::Alignment(gui::Alignment::ALIGN_HORIZONTAL_LEFT, gui::Alignment::ALIGN_VERTICAL_BOTTOM)); + label->setEdges( RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES ); + labelLines.push_back( label ); + startY += font->info.line_height; + } + + //assign text to all lines + auto textIterator = firstLine; + for( uint32_t i=0; isetText( (*textIterator)->text ); + lastLine = textIterator; + textIterator++; + + } +} + +void Text::setMargins( const Margins& margins ) { + this->margins = margins; + recalculateDrawParams(); +} + } /* namespace gui */ diff --git a/module-gui/gui/widgets/Text.hpp b/module-gui/gui/widgets/Text.hpp index ffa38d795..5dcfac3e9 100644 --- a/module-gui/gui/widgets/Text.hpp +++ b/module-gui/gui/widgets/Text.hpp @@ -10,6 +10,7 @@ #define MODULE_GUI_GUI_WIDGETS_TEXT_HPP_ #include +#include #include "utf8/UTF8.hpp" @@ -78,7 +79,7 @@ protected: //holds list of all lines that text was divided to. std::list textLines; //holds list of labels for displaying currently visible text lines. - std::list labelLines; + std::vector labelLines; //pointer to the first visible line of text std::list::iterator firstLine = textLines.end(); //pointer to the last visible line. @@ -86,7 +87,7 @@ protected: //row where cursor is located ( 0 - first row from top ) uint32_t cursorRow = 0; // column where cursor is located( 0 - position before first character in the line ) - uint32_t cursotColumn = 0; + uint32_t cursorColumn = 0; @@ -101,7 +102,10 @@ protected: Font* font; //index of the first visible row of the text uint32_t firstRow = 0; - //internal copy of the text that is displayed + //number of visible rows + + //margins for text + Margins margins; void splitTextToLines( const UTF8& text); /** @@ -109,7 +113,7 @@ protected: * Function stops on the last line or it there is a lines break ( enter ) or if last concatenated line doesn;t change after update. */ - void reworkLines( TextLine* textLine ); + void reworkLines( std::list::iterator it ); /** * Moves cursor in specified direction */ @@ -139,6 +143,15 @@ protected: * Returns text line where cursor is located */ TextLine* getCursorTextLine(); + /** + * Returns horizontal pixel space available for text. + */ + uint32_t getAvailableHPixelSpace() { + int32_t space = widgetArea.w - margins.left - margins.right; + return (space < 0 )?0:space; + } + + void recalculateDrawParams(); public: Text(); @@ -152,6 +165,7 @@ public: virtual void clear(); virtual UTF8 getText(); void setFont( const UTF8& fontName ); + virtual void setMargins( const Margins& margins ); //virtual methods from Item std::list buildDrawList() override; diff --git a/module-utils/utf8/UTF8.cpp b/module-utils/utf8/UTF8.cpp index b4c3ccc82..0a47a9e93 100644 --- a/module-utils/utf8/UTF8.cpp +++ b/module-utils/utf8/UTF8.cpp @@ -714,7 +714,7 @@ uint32_t UTF8::decode( const char* utf8_char, uint32_t& length ) const { uint32_t ret = 0; uint32_t len = 0; - //check if provided char is standars US-ASCII character. 0xxxxxxx + //check if provided char is standards US-ASCII character. 0xxxxxxx if( ( (*utf8_char) & UTF8_HEADER_1_MASK ) == 0 ) { ret = *utf8_char;