From c92e04802108d81c21dd932dfc528fb602c2e03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Wed, 24 Jun 2020 16:42:19 -0300 Subject: [PATCH] Minor optimizations for the StyleSheetParser. Added more menus for the Code Editor. Code Editor now saves the basic configuration. Renamed NodeMessage::Click to NodeMessage::MouseClick and NodeMessage::DoubleClick to NodeMessage::MouseDoubleClick to maintain consistency. Optimized String::split. And also some other minor improvements. --- bin/assets/colorschemes/colorschemes.conf | 14 +- bin/assets/layouts/test_widgets.xml | 2 +- bin/assets/ui/breeze.css | 2 - include/eepp/core/string.hpp | 7 +- include/eepp/scene/node.hpp | 6 +- include/eepp/scene/nodemessage.hpp | 4 +- include/eepp/ui/css/stylesheetparser.hpp | 3 +- include/eepp/ui/uitooltip.hpp | 2 +- src/eepp/core/string.cpp | 94 ++--- src/eepp/maps/mapeditor/uimap.cpp | 2 +- src/eepp/scene/eventdispatcher.cpp | 11 +- src/eepp/scene/node.cpp | 18 +- src/eepp/ui/css/stylesheetparser.cpp | 5 +- .../ui/css/stylesheetpropertiesparser.cpp | 8 +- src/eepp/ui/doc/syntaxdefinitionmanager.cpp | 17 + src/eepp/ui/uicheckbox.cpp | 2 +- src/eepp/ui/uicombobox.cpp | 2 +- src/eepp/ui/uifiledialog.cpp | 4 +- src/eepp/ui/uimenu.cpp | 4 +- src/eepp/ui/uimessagebox.cpp | 2 +- src/eepp/ui/uipushbutton.cpp | 2 +- src/eepp/ui/uiscrollbar.cpp | 2 +- src/eepp/ui/uispinbox.cpp | 2 +- src/eepp/ui/uitab.cpp | 2 +- src/eepp/ui/uitablecell.cpp | 2 +- src/eepp/ui/uitextview.cpp | 16 +- src/eepp/ui/uitheme.cpp | 2 +- src/eepp/ui/uithememanager.cpp | 2 +- src/eepp/ui/uitooltip.cpp | 22 +- src/eepp/ui/uiwindow.cpp | 2 +- src/tools/codeeditor/codeeditor.cpp | 325 +++++++++++++++--- src/tools/codeeditor/codeeditor.hpp | 41 +++ 32 files changed, 439 insertions(+), 190 deletions(-) diff --git a/bin/assets/colorschemes/colorschemes.conf b/bin/assets/colorschemes/colorschemes.conf index b0c30f1f0..8202611d8 100644 --- a/bin/assets/colorschemes/colorschemes.conf +++ b/bin/assets/colorschemes/colorschemes.conf @@ -38,16 +38,16 @@ line_break_column = #54575b99 matching_bracket = #FFFFFF33 matching_selection = #FFFFFF33 -normal = #cfcfcf -symbol = #cfcfcf -comment = #94b633 -keyword = #66bfff,shadow -keyword2 = #8abdff,shadow +normal = #e1e1e6 +symbol = #e1e1e6 +comment = #cd8b00 +keyword = #ff79c6,shadow +keyword2 = #8be9fd,shadow number = #ffd24a literal = #f1fa8c,shadow string = #ffcd8b -operator = #f051bb -function = #6ae0f9,shadow +operator = #51f0e7 +function = #00dc7f,shadow link = #6ae0f9,shadow,underline,#FFFFFF11 [fall] diff --git a/bin/assets/layouts/test_widgets.xml b/bin/assets/layouts/test_widgets.xml index 1f0085326..6fd46d330 100644 --- a/bin/assets/layouts/test_widgets.xml +++ b/bin/assets/layouts/test_widgets.xml @@ -3,7 +3,7 @@ - + diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index b60721ffe..add5d180e 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -61,7 +61,6 @@ Tooltip, MenuBar::button, Window::title { color: var(--font); - font-size: 11dp; } TextView, @@ -203,7 +202,6 @@ TextInputPassword { border-radius: var(--button-radius); border-width: var(--border-width); hint-color: var(--font-hint); - hint-font-size: 11dp; transition: all 0.15; } diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index 55a8fdbfc..39aef5056 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -56,9 +56,6 @@ class EE_API String { static const std::size_t InvalidPos; ///< Represents an invalid position in the string - /** @return string hash */ - static constexpr HashType hash( const Uint8* str ); - /** @return string hash */ static constexpr HashType hash( const char* str ) { //! djb2 @@ -98,11 +95,11 @@ class EE_API String { static bool isHexNotation( const std::string& value, const std::string& withPrefix = "" ); /** Split a String and hold it on a vector */ - static std::vector split( const String& str, const Uint32& splitchar = '\n', + static std::vector split( const String& str, const Uint32& delim = '\n', const bool& pushEmptyString = false ); /** Split a string and hold it on a vector */ - static std::vector split( const std::string& str, const Int8& splitchar = '\n', + static std::vector split( const std::string& str, const Int8& delim = '\n', const bool& pushEmptyString = false ); /** Split a string and hold it on a vector. This function is meant to be used for code diff --git a/include/eepp/scene/node.hpp b/include/eepp/scene/node.hpp index 0ff6c74c2..afa8c21f3 100644 --- a/include/eepp/scene/node.hpp +++ b/include/eepp/scene/node.hpp @@ -188,9 +188,11 @@ class EE_API Node : public Transformable { bool isMeOrParentTreeScaledOrRotatedOrFrameBuffer() const; - Uint32 addEventListener( const Uint32& EventType, const EventCallback& Callback ); + Uint32 addEventListener( const Uint32& eventType, const EventCallback& callback ); - void removeEventListener( const Uint32& CallbackId ); + void removeEventsOfType( const Uint32& eventType ); + + void removeEventListener( const Uint32& callbackId ); Node* getFirstChild() const; diff --git a/include/eepp/scene/nodemessage.hpp b/include/eepp/scene/nodemessage.hpp index 64bf510a6..dc15ceceb 100644 --- a/include/eepp/scene/nodemessage.hpp +++ b/include/eepp/scene/nodemessage.hpp @@ -10,8 +10,8 @@ class Node; class EE_API NodeMessage { public: enum Message { - Click = 0, - DoubleClick, + MouseClick = 0, + MouseDoubleClick, MouseOver, MouseLeave, MouseDown, diff --git a/include/eepp/ui/css/stylesheetparser.hpp b/include/eepp/ui/css/stylesheetparser.hpp index e22c08f38..013d7d1d1 100644 --- a/include/eepp/ui/css/stylesheetparser.hpp +++ b/include/eepp/ui/css/stylesheetparser.hpp @@ -63,8 +63,7 @@ class EE_API StyleSheetParser { void importParse( std::string& css, std::size_t& pos, std::string& buffer, std::vector& importedList ); - void keyframesParse( std::string& css, ReadState& rs, std::size_t& pos, std::string& buffer, - std::vector& importedList ); + void keyframesParse( std::string& css, ReadState& rs, std::size_t& pos, std::string& buffer ); }; }}} // namespace EE::UI::CSS diff --git a/include/eepp/ui/uitooltip.hpp b/include/eepp/ui/uitooltip.hpp index da546c952..5591ebd1b 100644 --- a/include/eepp/ui/uitooltip.hpp +++ b/include/eepp/ui/uitooltip.hpp @@ -71,7 +71,7 @@ class EE_API UITooltip : public UIWidget { Uint32 getCharacterSize() const; - UITooltip* setCharacterSize( const Uint32& characterSize ); + UITooltip* setFontSize( const Uint32& characterSize ); UITooltip* setFontStyle( const Uint32& fontStyle ); diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 147e882a9..58dcb4bfb 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -10,21 +10,6 @@ namespace EE { const std::size_t String::InvalidPos = StringType::npos; -constexpr String::HashType String::hash( const Uint8* str ) { - //! djb2 - if ( NULL != str ) { - Uint32 hash = 5381; - Int32 c = 0; - - while ( ( c = *str++ ) ) - hash = ( ( hash << 5 ) + hash ) + c; - - return hash; - } - - return 0; -} - String::HashType String::hash( const std::string& str ) { return String::hash( str.c_str() ); } @@ -67,26 +52,22 @@ bool String::isHexNotation( const std::string& value, const std::string& withPre std::string::npos; } -std::vector String::split( const String& str, const Uint32& splitchar, +std::vector String::split( const String& str, const Uint32& delim, const bool& pushEmptyString ) { - std::vector tmp; - String tmpstr; - - for ( unsigned int i = 0; i < str.size(); i++ ) { - if ( str[i] == splitchar ) { - if ( pushEmptyString || tmpstr.size() ) { - tmp.push_back( tmpstr ); - tmpstr = ""; - } - } else { - tmpstr += str[i]; - } + std::vector cont; + std::size_t current, previous = 0; + current = str.find( delim ); + while ( current != String::InvalidPos ) { + String substr( str.substr( previous, current - previous ) ); + if ( pushEmptyString || !substr.empty() ) + cont.emplace_back( std::move( substr ) ); + previous = current + 1; + current = str.find( delim, previous ); } - - if ( tmpstr.size() ) - tmp.push_back( tmpstr ); - - return tmp; + String substr( str.substr( previous, current - previous ) ); + if ( pushEmptyString || !substr.empty() ) + cont.emplace_back( std::move( substr ) ); + return cont; } std::vector String::split( const std::string& str, const std::string& delims, @@ -148,26 +129,22 @@ std::vector String::split( const std::string& str, const std::strin return tokens; } -std::vector String::split( const std::string& str, const Int8& splitchar, +std::vector String::split( const std::string& str, const Int8& delim, const bool& pushEmptyString ) { - std::vector tmp; - std::string tmpstr; - - for ( unsigned int i = 0; i < str.size(); i++ ) { - if ( str[i] == splitchar ) { - if ( pushEmptyString || tmpstr.size() ) { - tmp.push_back( tmpstr ); - tmpstr = ""; - } - } else { - tmpstr += str[i]; - } + std::vector cont; + std::size_t current, previous = 0; + current = str.find( delim ); + while ( current != std::string::npos ) { + std::string substr( str.substr( previous, current - previous ) ); + if ( pushEmptyString || !substr.empty() ) + cont.emplace_back( std::move( substr ) ); + previous = current + 1; + current = str.find( delim, previous ); } - - if ( tmpstr.size() ) - tmp.push_back( tmpstr ); - - return tmp; + std::string substr( str.substr( previous, current - previous ) ); + if ( pushEmptyString || !substr.empty() ) + cont.emplace_back( std::move( substr ) ); + return cont; } std::string String::join( const std::vector& strArray, const Int8& joinchar, @@ -344,19 +321,15 @@ void String::replaceAll( String& target, const String& that, const String& with void String::replace( std::string& target, const std::string& that, const std::string& with ) { std::size_t start_pos = target.find( that ); - if ( start_pos == std::string::npos ) return; - target.replace( start_pos, that.length(), with ); } void String::replace( String& target, const String& that, const String& with ) { std::size_t start_pos = target.find( that ); - if ( start_pos == String::InvalidPos ) return; - target.replace( start_pos, that.length(), with ); } @@ -364,25 +337,22 @@ std::string String::removeNumbersAtEnd( std::string txt ) { while ( txt.size() && txt[txt.size() - 1] >= '0' && txt[txt.size() - 1] <= '9' ) { txt.resize( txt.size() - 1 ); } - return txt; } std::size_t String::findCloseBracket( const std::string& string, std::size_t startOffset, char openBracket, char closeBracket ) { int count = 0; - - for ( size_t i = startOffset; i < string.size(); i++ ) { + size_t len = string.size(); + for ( size_t i = startOffset; i < len; i++ ) { if ( string[i] == openBracket ) { count++; } else if ( string[i] == closeBracket ) { count--; - if ( 0 == count ) { + if ( 0 == count ) return i; - } } } - return std::string::npos; } @@ -928,7 +898,7 @@ std::size_t String::copy( StringBaseType* s, std::size_t n, std::size_t pos ) co } String String::substr( std::size_t pos, std::size_t n ) const { - return String( mString.substr( pos, n ) ); + return mString.substr( pos, n ); } int String::compare( const String& str ) const { diff --git a/src/eepp/maps/mapeditor/uimap.cpp b/src/eepp/maps/mapeditor/uimap.cpp index feabd7054..af9734513 100644 --- a/src/eepp/maps/mapeditor/uimap.cpp +++ b/src/eepp/maps/mapeditor/uimap.cpp @@ -545,7 +545,7 @@ void UIMap::setUpdateScrollCb( UpdateScrollCb Cb ) { } Uint32 UIMap::onMessage( const NodeMessage* Msg ) { - if ( Msg->getMsg() == NodeMessage::Click && Msg->getSender() == this && + if ( Msg->getMsg() == NodeMessage::MouseClick && Msg->getSender() == this && ( Msg->getFlags() & EE_BUTTON_RMASK ) ) { if ( SELECT_OBJECTS == mEditingObjMode && NULL != mSelObj && mSelObj->pointInside( mMap->getMouseMapPosf() ) ) { diff --git a/src/eepp/scene/eventdispatcher.cpp b/src/eepp/scene/eventdispatcher.cpp index 45cc650d2..0a57f8d4b 100644 --- a/src/eepp/scene/eventdispatcher.cpp +++ b/src/eepp/scene/eventdispatcher.cpp @@ -116,26 +116,25 @@ void EventDispatcher::update( const Time& time ) { setFocusNode( mOverNode ); // The focused node can change after the MouseUp ( since the node can call - // "setFocus()" on other node And the Click would be received by the new focused - // node instead of the real one + // "setFocus()" on other node And the MouseClick would be received by the new + // focused node instead of the real one Node* lastFocusNode = mFocusNode; if ( NULL != mOverNode ) { getMouseOverNode()->onMouseUp( mMousePosi, mInput->getReleaseTrigger() ); - if ( NULL != mOverNode ) sendMsg( mOverNode, NodeMessage::MouseUp, mInput->getReleaseTrigger() ); } if ( mInput->getClickTrigger() ) { lastFocusNode->onMouseClick( mMousePosi, mInput->getClickTrigger() ); - sendMsg( lastFocusNode, NodeMessage::Click, mInput->getClickTrigger() ); + sendMsg( lastFocusNode, NodeMessage::MouseClick, mInput->getClickTrigger() ); if ( mInput->getDoubleClickTrigger() && mClickPos.distance( mMousePosi ) < 10 ) { lastFocusNode->onMouseDoubleClick( mMousePosi, mInput->getDoubleClickTrigger() ); - sendMsg( lastFocusNode, NodeMessage::DoubleClick, + sendMsg( lastFocusNode, NodeMessage::MouseDoubleClick, mInput->getDoubleClickTrigger() ); } @@ -199,7 +198,7 @@ void EventDispatcher::sendMsg( Node* node, const Uint32& Msg, const Uint32& Flag } void EventDispatcher::sendMouseClick( Node* toNode, const Vector2i& Pos, const Uint32 flags ) { - sendMsg( toNode, NodeMessage::Click, flags ); + sendMsg( toNode, NodeMessage::MouseClick, flags ); toNode->onMouseClick( Pos, flags ); } diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index 07d083a90..82c67533e 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1050,21 +1050,23 @@ void Node::updateCenter() { mScreenPos.y + (Float)mSize.getHeight() * 0.5f ); } -Uint32 Node::addEventListener( const Uint32& EventType, const EventCallback& Callback ) { +Uint32 Node::addEventListener( const Uint32& eventType, const EventCallback& callback ) { mNumCallBacks++; - - mEvents[EventType][mNumCallBacks] = Callback; - + mEvents[eventType][mNumCallBacks] = callback; return mNumCallBacks; } -void Node::removeEventListener( const Uint32& CallbackId ) { - EventsMap::iterator it; +void Node::removeEventsOfType( const Uint32& eventType ) { + auto it = mEvents.find( eventType ); + if ( it != mEvents.end() ) + mEvents.erase( it ); +} +void Node::removeEventListener( const Uint32& callbackId ) { + EventsMap::iterator it; for ( it = mEvents.begin(); it != mEvents.end(); ++it ) { std::map& event = it->second; - - if ( event.erase( CallbackId ) > 0 ) + if ( event.erase( callbackId ) > 0 ) break; } } diff --git a/src/eepp/ui/css/stylesheetparser.cpp b/src/eepp/ui/css/stylesheetparser.cpp index 1044b30cd..5b43776ef 100644 --- a/src/eepp/ui/css/stylesheetparser.cpp +++ b/src/eepp/ui/css/stylesheetparser.cpp @@ -110,7 +110,7 @@ bool StyleSheetParser::parse( std::string& css, std::vector& import } else if ( String::startsWith( buffer, "@import" ) ) { importParse( css, pos, buffer, importedList ); } else if ( String::startsWith( buffer, "@keyframes" ) ) { - keyframesParse( css, rs, pos, buffer, importedList ); + keyframesParse( css, rs, pos, buffer ); } } @@ -344,8 +344,7 @@ void StyleSheetParser::importParse( std::string& css, std::size_t& pos, std::str } void StyleSheetParser::keyframesParse( std::string& css, ReadState& rs, std::size_t& pos, - std::string& buffer, - std::vector& importedList ) { + std::string& buffer ) { std::size_t keyframesClosePos = String::findCloseBracket( css, pos - 1, '{', '}' ); if ( keyframesClosePos != std::string::npos ) { diff --git a/src/eepp/ui/css/stylesheetpropertiesparser.cpp b/src/eepp/ui/css/stylesheetpropertiesparser.cpp index e818a1b2b..57abed3d3 100644 --- a/src/eepp/ui/css/stylesheetpropertiesparser.cpp +++ b/src/eepp/ui/css/stylesheetpropertiesparser.cpp @@ -146,13 +146,13 @@ void StyleSheetPropertiesParser::addProperty( std::string name, std::string valu StyleSheetSpecification::instance()->getShorthand( name )->parse( value ); for ( auto& property : properties ) - mProperties[property.getId()] = property; + mProperties.emplace( std::make_pair( property.getId(), std::move( property ) ) ); } else { if ( String::startsWith( name, "--" ) ) { - mVariables[String::hash(name)] = StyleSheetVariable( name, value ); + mVariables[String::hash( name )] = StyleSheetVariable( name, value ); } else { - StyleSheetProperty property( StyleSheetProperty( name, value ) ); - mProperties[property.getId()] = property; + StyleSheetProperty property( name, value ); + mProperties.emplace( std::make_pair( property.getId(), std::move( property ) ) ); } } } diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index f28e9629e..4abb1e52d 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -260,6 +260,8 @@ SyntaxDefinitionManager::SyntaxDefinitionManager() { {{"-?%.?%d+f?"}, "number"}, {{"[%+%-=/%*%^%%<>!~|&]"}, "operator"}, {{"[%a_][%w_]*%f[(]"}, "function"}, + {{"std%:%:[%w_]-%<.-%>"}, "keyword2"}, + {{"std%:%:.-%s"}, "keyword2"}, {{"[%a_][%w_]*"}, "symbol"}, }, { @@ -364,6 +366,21 @@ SyntaxDefinitionManager::SyntaxDefinitionManager() { {"uint16_t", "keyword2"}, {"uint32_t", "keyword2"}, {"uint64_t", "keyword2"}, + {"String", "keyword2"}, + {"Int8", "keyword2"}, + {"Uint8", "keyword2"}, + {"Int16", "keyword2"}, + {"Uint16", "keyword2"}, + {"Int32", "keyword2"}, + {"Uint32", "keyword2"}, + {"Int64", "keyword2"}, + {"Uint64", "keyword2"}, + {"Float", "keyword2"}, + {"Color", "keyword2"}, + {"Vector2f", "keyword2"}, + {"Vector2i", "keyword2"}, + {"Recti", "keyword2"}, + {"Rectf", "keyword2"}, {"NULL", "literal"}, }, "//"} ); diff --git a/src/eepp/ui/uicheckbox.cpp b/src/eepp/ui/uicheckbox.cpp index bdf7deee9..57e177db1 100644 --- a/src/eepp/ui/uicheckbox.cpp +++ b/src/eepp/ui/uicheckbox.cpp @@ -107,7 +107,7 @@ void UICheckBox::onSizeChange() { Uint32 UICheckBox::onMessage( const NodeMessage* Msg ) { switch ( Msg->getMsg() ) { - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( Msg->getFlags() & EE_BUTTON_LMASK ) { switchState(); } diff --git a/src/eepp/ui/uicombobox.cpp b/src/eepp/ui/uicombobox.cpp index 53f8ad957..fb4f0f244 100644 --- a/src/eepp/ui/uicombobox.cpp +++ b/src/eepp/ui/uicombobox.cpp @@ -81,7 +81,7 @@ void UIComboBox::loadFromXmlNode( const pugi::xml_node& node ) { } Uint32 UIComboBox::onMessage( const NodeMessage* Msg ) { - if ( Msg->getMsg() == NodeMessage::Click && Msg->getSender() == mButton && + if ( Msg->getMsg() == NodeMessage::MouseClick && Msg->getSender() == mButton && ( Msg->getFlags() & EE_BUTTON_LMASK && NULL != mDropDownList ) ) { mDropDownList->showList(); } diff --git a/src/eepp/ui/uifiledialog.cpp b/src/eepp/ui/uifiledialog.cpp index 0b5a46f57..b9ef5209f 100644 --- a/src/eepp/ui/uifiledialog.cpp +++ b/src/eepp/ui/uifiledialog.cpp @@ -303,7 +303,7 @@ void UIFileDialog::goFolderUp() { Uint32 UIFileDialog::onMessage( const NodeMessage* Msg ) { switch ( Msg->getMsg() ) { - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( Msg->getFlags() & EE_BUTTON_LMASK ) { if ( Msg->getSender() == mButtonOpen ) { openSaveClick(); @@ -318,7 +318,7 @@ Uint32 UIFileDialog::onMessage( const NodeMessage* Msg ) { break; } - case NodeMessage::DoubleClick: { + case NodeMessage::MouseDoubleClick: { if ( Msg->getFlags() & EE_BUTTON_LMASK ) { if ( Msg->getSender()->isType( UI_TYPE_LISTBOXITEM ) ) { openFileOrFolder(); diff --git a/src/eepp/ui/uimenu.cpp b/src/eepp/ui/uimenu.cpp index 5dfa919be..9d86c03d1 100644 --- a/src/eepp/ui/uimenu.cpp +++ b/src/eepp/ui/uimenu.cpp @@ -385,7 +385,9 @@ void UIMenu::safeHide() { menu->mCurrentSubMenu = nullptr; if ( mOwnerNode == menu->getItemSelected() ) menu->unselectSelected(); - menu->setFocus(); + if ( getEventDispatcher()->getFocusNode() == this || + isParentOf( getEventDispatcher()->getFocusNode() ) ) + menu->setFocus(); } unselectSelected(); if ( mCurrentSubMenu ) { diff --git a/src/eepp/ui/uimessagebox.cpp b/src/eepp/ui/uimessagebox.cpp index 1c5a5d1cd..095d0ba20 100644 --- a/src/eepp/ui/uimessagebox.cpp +++ b/src/eepp/ui/uimessagebox.cpp @@ -119,7 +119,7 @@ void UIMessageBox::setTheme( UITheme* theme ) { Uint32 UIMessageBox::onMessage( const NodeMessage* Msg ) { switch ( Msg->getMsg() ) { - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( Msg->getFlags() & EE_BUTTON_LMASK ) { if ( Msg->getSender() == mButtonOK ) { sendCommonEvent( Event::MsgBoxConfirmClick ); diff --git a/src/eepp/ui/uipushbutton.cpp b/src/eepp/ui/uipushbutton.cpp index d38c72da9..b01c21698 100644 --- a/src/eepp/ui/uipushbutton.cpp +++ b/src/eepp/ui/uipushbutton.cpp @@ -281,7 +281,7 @@ void UIPushButton::onAlignChange() { Uint32 UIPushButton::onKeyDown( const KeyEvent& Event ) { if ( Event.getKeyCode() == KEY_RETURN ) { - NodeMessage Msg( this, NodeMessage::Click, EE_BUTTON_LMASK ); + NodeMessage Msg( this, NodeMessage::MouseClick, EE_BUTTON_LMASK ); messagePost( &Msg ); onMouseClick( Vector2i( 0, 0 ), EE_BUTTON_LMASK ); pushState( UIState::StatePressed ); diff --git a/src/eepp/ui/uiscrollbar.cpp b/src/eepp/ui/uiscrollbar.cpp index a3f776804..721f0caae 100644 --- a/src/eepp/ui/uiscrollbar.cpp +++ b/src/eepp/ui/uiscrollbar.cpp @@ -251,7 +251,7 @@ void UIScrollBar::adjustChilds() { Uint32 UIScrollBar::onMessage( const NodeMessage* Msg ) { switch ( Msg->getMsg() ) { - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( Msg->getFlags() & EE_BUTTON_LMASK ) { if ( Msg->getSender() == mBtnUp ) { mSlider->setValue( getValue() - getClickStep() ); diff --git a/src/eepp/ui/uispinbox.cpp b/src/eepp/ui/uispinbox.cpp index f402267d6..4222084e3 100644 --- a/src/eepp/ui/uispinbox.cpp +++ b/src/eepp/ui/uispinbox.cpp @@ -129,7 +129,7 @@ const double& UISpinBox::getClickStep() const { Uint32 UISpinBox::onMessage( const NodeMessage* Msg ) { switch ( Msg->getMsg() ) { - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( Msg->getFlags() & EE_BUTTON_LMASK ) { if ( Msg->getSender() == mPushUp ) { addValue( mClickStep ); diff --git a/src/eepp/ui/uitab.cpp b/src/eepp/ui/uitab.cpp index d4d6b53b8..1d3f6a50d 100644 --- a/src/eepp/ui/uitab.cpp +++ b/src/eepp/ui/uitab.cpp @@ -297,7 +297,7 @@ Uint32 UITab::onMessage( const NodeMessage* message ) { } break; } - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( flags & EE_BUTTON_LMASK && message->getSender() == mCloseButton ) { tTabW->tryCloseTab( this ); } diff --git a/src/eepp/ui/uitablecell.cpp b/src/eepp/ui/uitablecell.cpp index 8aac6938c..16197b1b3 100644 --- a/src/eepp/ui/uitablecell.cpp +++ b/src/eepp/ui/uitablecell.cpp @@ -113,7 +113,7 @@ Uint32 UITableCell::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) { Uint32 UITableCell::onMessage( const NodeMessage* Msg ) { switch ( Msg->getMsg() ) { - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( Msg->getFlags() & EE_BUTTONS_LRM ) { select(); diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index bd4ba9523..9b6d3c6c8 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -39,12 +39,6 @@ UITextView::UITextView( const std::string& tag ) : setFont( theme->getDefaultFont() ); } - if ( NULL != theme ) { - setFontSize( theme->getDefaultFontSize() ); - } else { - mTextCache->setFontSize( getUISceneNode()->getUIThemeManager()->getDefaultFontSize() ); - } - if ( NULL == getFont() ) { if ( NULL != getUISceneNode()->getUIThemeManager()->getDefaultFont() ) { setFont( getUISceneNode()->getUIThemeManager()->getDefaultFont() ); @@ -53,6 +47,12 @@ UITextView::UITextView( const std::string& tag ) : } } + if ( NULL != theme ) { + setFontSize( theme->getDefaultFontSize() ); + } else { + setFontSize( getUISceneNode()->getUIThemeManager()->getDefaultFontSize() ); + } + applyDefaultTheme(); } @@ -383,7 +383,7 @@ Uint32 UITextView::onMouseDoubleClick( const Vector2i& Pos, const Uint32& Flags Vector2f nodePos( Vector2f( Pos.x, Pos.y ) ); worldToNode( nodePos ); nodePos = PixelDensity::dpToPx( nodePos ) - mRealAlignOffset - - Vector2f( mRealPadding.Left, mRealPadding.Top ); + Vector2f( mRealPadding.Left, mRealPadding.Top ); nodePos.x = eemax( 0.f, nodePos.x ); nodePos.y = eemax( 0.f, nodePos.y ); @@ -419,7 +419,7 @@ Uint32 UITextView::onMouseDown( const Vector2i& Pos, const Uint32& Flags ) { Vector2f nodePos( Vector2f( Pos.x, Pos.y ) ); worldToNode( nodePos ); nodePos = PixelDensity::dpToPx( nodePos ) - mRealAlignOffset - - Vector2f( mRealPadding.Left, mRealPadding.Top ); + Vector2f( mRealPadding.Left, mRealPadding.Top ); nodePos.x = eemax( 0.f, nodePos.x ); nodePos.y = eemax( 0.f, nodePos.y ); diff --git a/src/eepp/ui/uitheme.cpp b/src/eepp/ui/uitheme.cpp index d07d77da9..10c06c5b0 100644 --- a/src/eepp/ui/uitheme.cpp +++ b/src/eepp/ui/uitheme.cpp @@ -262,7 +262,7 @@ UITheme::UITheme( const std::string& name, const std::string& Abbr, Graphics::Fo mAbbr( Abbr ), mTextureAtlas( NULL ), mDefaultFont( defaultFont ), - mDefaultFontSize( 12 ) {} + mDefaultFontSize( PixelDensity::getPixelDensity() > 1.4 ? 11 : 12 ) {} UITheme::~UITheme() {} diff --git a/src/eepp/ui/uithememanager.cpp b/src/eepp/ui/uithememanager.cpp index cd21c211c..eb5cb6f42 100644 --- a/src/eepp/ui/uithememanager.cpp +++ b/src/eepp/ui/uithememanager.cpp @@ -10,7 +10,7 @@ UIThemeManager* UIThemeManager::New() { UIThemeManager::UIThemeManager() : ResourceManager(), mFont( NULL ), - mFontSize( 12 ), + mFontSize( PixelDensity::getPixelDensity() > 1.4 ? 11 : 12 ), mThemeDefault( NULL ), mAutoApplyDefaultTheme( true ), mEnableDefaultEffects( false ), diff --git a/src/eepp/ui/uitooltip.cpp b/src/eepp/ui/uitooltip.cpp index f80088536..7283c8d5e 100644 --- a/src/eepp/ui/uitooltip.cpp +++ b/src/eepp/ui/uitooltip.cpp @@ -20,17 +20,25 @@ UITooltip::UITooltip() : mTextCache = Text::New(); mEnabled = false; + UITheme* theme = getUISceneNode()->getUIThemeManager()->getDefaultTheme(); - if ( NULL != theme ) { - mStyleConfig.Font = theme->getDefaultFont(); + if ( NULL != theme && NULL != theme->getDefaultFont() ) { + setFont( theme->getDefaultFont() ); } if ( NULL == getFont() ) { - if ( NULL != getUISceneNode()->getUIThemeManager()->getDefaultFont() ) + if ( NULL != getUISceneNode()->getUIThemeManager()->getDefaultFont() ) { setFont( getUISceneNode()->getUIThemeManager()->getDefaultFont() ); - else - eePRINTL( "UITooltip::UITooltip : Created a without a defined font." ); + } else { + eePRINTL( "UITextView::UITextView : Created a without a defined font." ); + } + } + + if ( NULL != theme ) { + setFontSize( theme->getDefaultFontSize() ); + } else { + setFontSize( getUISceneNode()->getUIThemeManager()->getDefaultFontSize() ); } autoPadding(); @@ -259,7 +267,7 @@ Uint32 UITooltip::getCharacterSize() const { return mTextCache->getCharacterSize(); } -UITooltip* UITooltip::setCharacterSize( const Uint32& characterSize ) { +UITooltip* UITooltip::setFontSize( const Uint32& characterSize ) { if ( mTextCache->getCharacterSize() != characterSize ) { mStyleConfig.CharacterSize = characterSize; mTextCache->setFontSize( characterSize ); @@ -390,7 +398,7 @@ bool UITooltip::applyProperty( const StyleSheetProperty& attribute ) { break; } case PropertyId::FontSize: - setCharacterSize( attribute.asDpDimensionI() ); + setFontSize( attribute.asDpDimensionI() ); break; case PropertyId::FontStyle: setFontStyle( attribute.asFontStyle() ); diff --git a/src/eepp/ui/uiwindow.cpp b/src/eepp/ui/uiwindow.cpp index e787b56d3..a78749189 100644 --- a/src/eepp/ui/uiwindow.cpp +++ b/src/eepp/ui/uiwindow.cpp @@ -796,7 +796,7 @@ Uint32 UIWindow::onMessage( const NodeMessage* Msg ) { getUISceneNode()->setCursor( Cursor::Arrow ); break; } - case NodeMessage::Click: { + case NodeMessage::MouseClick: { if ( ( mStyleConfig.WinFlags & UI_WIN_USE_DEFAULT_BUTTONS_ACTIONS ) && ( Msg->getFlags() & EE_BUTTON_LMASK ) ) { if ( Msg->getSender() == mButtonClose ) { diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index b806b02a6..aed938e2b 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -1,20 +1,20 @@ #include "codeeditor.hpp" #include -App* appInstance = NULL; +App* appInstance = nullptr; void appLoop() { appInstance->mainLoop(); } bool App::onCloseRequestCallback( EE::Window::Window* ) { - if ( NULL != mCurEditor && mCurEditor->isDirty() ) { + if ( nullptr != mCurEditor && mCurEditor->isDirty() ) { mMsgBox = UIMessageBox::New( UIMessageBox::OK_CANCEL, "Do you really want to close the code editor?\nAll changes will be lost." ); mMsgBox->addEventListener( Event::MsgBoxConfirmClick, [&]( const Event* ) { mWindow->close(); } ); - mMsgBox->addEventListener( Event::OnClose, [&]( const Event* ) { mMsgBox = NULL; } ); + mMsgBox->addEventListener( Event::OnClose, [&]( const Event* ) { mMsgBox = nullptr; } ); mMsgBox->setTitle( "Close Code Editor?" ); mMsgBox->center(); mMsgBox->show(); @@ -25,14 +25,14 @@ bool App::onCloseRequestCallback( EE::Window::Window* ) { } bool App::tryTabClose( UICodeEditor* editor ) { - if ( NULL != editor && editor->isDirty() ) { + if ( nullptr != editor && editor->isDirty() ) { mMsgBox = UIMessageBox::New( UIMessageBox::OK_CANCEL, "Do you really want to close this tab?\nAll changes will be lost." ); mMsgBox->addEventListener( Event::MsgBoxConfirmClick, [&, editor]( const Event* ) { closeEditorTab( editor ); } ); mMsgBox->addEventListener( Event::OnClose, [&]( const Event* ) { - mMsgBox = NULL; + mMsgBox = nullptr; if ( mCurEditor ) mCurEditor->setFocus(); } ); @@ -70,7 +70,7 @@ void App::splitEditor( const SplitDirection& direction, UICodeEditor* editor ) { if ( !tabWidget ) return; Node* parent = tabWidget->getParent(); - UISplitter* parentSplitter = NULL; + UISplitter* parentSplitter = nullptr; bool wasFirst = true; if ( parent->isType( UI_TYPE_SPLITTER ) ) { @@ -113,10 +113,10 @@ void App::switchToTab( Int32 index ) { UITabWidget* App::findPreviousSplit( UICodeEditor* editor ) { if ( !editor ) - return NULL; + return nullptr; UISplitter* splitter = splitterFromEditor( editor ); if ( !splitter ) - return NULL; + return nullptr; UITabWidget* tabWidget = tabWidgetFromEditor( editor ); if ( tabWidget ) { auto it = std::find( mTabWidgets.rbegin(), mTabWidgets.rend(), tabWidget ); @@ -124,7 +124,7 @@ UITabWidget* App::findPreviousSplit( UICodeEditor* editor ) { return *it; } } - return NULL; + return nullptr; } void App::switchPreviousSplit( UICodeEditor* editor ) { @@ -143,10 +143,10 @@ void App::switchPreviousSplit( UICodeEditor* editor ) { UITabWidget* App::findNextSplit( UICodeEditor* editor ) { if ( !editor ) - return NULL; + return nullptr; UISplitter* splitter = splitterFromEditor( editor ); if ( !splitter ) - return NULL; + return nullptr; UITabWidget* tabWidget = tabWidgetFromEditor( editor ); if ( tabWidget ) { auto it = std::find( mTabWidgets.begin(), mTabWidgets.end(), tabWidget ); @@ -154,7 +154,7 @@ UITabWidget* App::findNextSplit( UICodeEditor* editor ) { return *it; } } - return NULL; + return nullptr; } void App::switchNextSplit( UICodeEditor* editor ) { @@ -190,11 +190,22 @@ void App::saveDoc() { } } +void App::forEachEditor( std::function run ) { + for ( auto tabWidget : mTabWidgets ) + for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) + run( tabWidget->getTab( i )->getOwnedWidget()->asType() ); +} + UICodeEditor* App::createCodeEditor() { UICodeEditor* codeEditor = UICodeEditor::NewOpt( false, true ); - codeEditor->setFontSize( 11 ); + codeEditor->setFontSize( mConfig.editor.fontSize ); codeEditor->setEnableColorPickerOnSelection( true ); codeEditor->setColorScheme( mColorSchemes[mCurrentColorScheme] ); + codeEditor->setShowLineNumber( mConfig.editor.showLineNumbers ); + codeEditor->setShowWhitespaces( mConfig.editor.showWhiteSpaces ); + codeEditor->setHighlightMatchingBracket( mConfig.editor.highlightMatchingBracket ); + codeEditor->setHorizontalScrollBarEnabled( mConfig.editor.horizontalScrollbar ); + codeEditor->setHighlightCurrentLine( mConfig.editor.highlightCurrentLine ); TextDocument& doc = codeEditor->getDocument(); /* global commands */ @@ -291,7 +302,7 @@ UICodeEditor* App::createCodeEditor() { doc.setCommand( "switch-to-next-split", [&] { switchNextSplit( mCurEditor ); } ); doc.setCommand( "save-doc", [&] { saveDoc(); } ); doc.setCommand( "save-as-doc", [&] { saveFileDialog(); } ); - doc.setCommand( "find", [&] { showFindView(); } ); + doc.setCommand( "find-replace", [&] { showFindView(); } ); doc.setCommand( "repeat-find", [&] { findNextText( "", mSearchBarLayout->find( "case_sensitive" )->isChecked() ); } ); @@ -301,11 +312,7 @@ UICodeEditor* App::createCodeEditor() { doc.setCommand( "console-toggle", [&] { mConsole->toggle(); bool lock = mConsole->isActive(); - for ( auto tabW : mTabWidgets ) { - for ( size_t i = 0; i < tabW->getTabCount(); i++ ) { - tabW->getTab( i )->getOwnedWidget()->asType()->setLocked( lock ); - } - } + forEachEditor( [lock]( UICodeEditor* editor ) { editor->setLocked( lock ); } ); } ); doc.setCommand( "close-doc", [&] { tryTabClose( mCurEditor ); } ); doc.setCommand( "create-new", [&] { @@ -341,8 +348,7 @@ UICodeEditor* App::createCodeEditor() { } ); codeEditor->addEventListener( Event::OnFocus, [&]( const Event* event ) { - mCurEditor = event->getNode()->asType(); - updateEditorState(); + setCurrentEditor( event->getNode()->asType() ); } ); codeEditor->addEventListener( Event::OnTextChanged, [&]( const Event* event ) { updateEditorTitle( event->getNode()->asType() ); @@ -357,7 +363,7 @@ UICodeEditor* App::createCodeEditor() { codeEditor->addKeyBindingString( "alt+return", "fullscreen-toggle", true ); codeEditor->addKeyBindingString( "alt+keypad enter", "fullscreen-toggle", true ); codeEditor->addKeyBindingString( "ctrl+s", "save-doc", false ); - codeEditor->addKeyBindingString( "ctrl+f", "find", false ); + codeEditor->addKeyBindingString( "ctrl+f", "find-replace", false ); codeEditor->addKeyBindingString( "ctrl+q", "close-app", true ); codeEditor->addKeyBindingString( "ctrl+o", "open-file", true ); codeEditor->addKeyBindingString( "ctrl+l", "lock-toggle", true ); @@ -382,8 +388,8 @@ UICodeEditor* App::createCodeEditor() { String::format( "switch-to-tab-%d", i ), true ); } - if ( NULL == mCurEditor ) { - mCurEditor = codeEditor; + if ( nullptr == mCurEditor ) { + setCurrentEditor( codeEditor ); } return codeEditor; } @@ -461,7 +467,7 @@ void App::closeSplitter( UISplitter* splitter ) { void App::onTabClosed( const TabEvent* tabEvent ) { UICodeEditor* editor = mCurEditor; if ( tabEvent->getTab()->getOwnedWidget() == mCurEditor ) { - mCurEditor = NULL; + setCurrentEditor( nullptr ); } UITabWidget* tabWidget = tabEvent->getTab()->getTabWidget(); if ( tabWidget->getTabCount() == 0 ) { @@ -498,7 +504,7 @@ void App::onTabClosed( const TabEvent* tabEvent ) { eeASSERT( parent->getChildCount() == 0 ); remainingNode->setParent( parent ); addRemainingTabWidgets( remainingNode ); - focusSomeEditor( NULL ); + focusSomeEditor( nullptr ); } return; } @@ -511,10 +517,10 @@ void App::onTabClosed( const TabEvent* tabEvent ) { } std::pair App::createCodeEditorInTabWidget( UITabWidget* tabWidget ) { - if ( NULL == tabWidget ) - return std::make_pair( (UITab*)NULL, (UICodeEditor*)NULL ); + if ( nullptr == tabWidget ) + return std::make_pair( (UITab*)nullptr, (UICodeEditor*)nullptr ); UICodeEditor* editor = createCodeEditor(); - editor->addEventListener( Event::OnDocumentChanged, [&] (const Event* event) { + editor->addEventListener( Event::OnDocumentChanged, [&]( const Event* event ) { updateEditorTitle( event->getNode()->asType() ); } ); UITab* tab = tabWidget->add( editor->getDocument().getFilename(), editor ); @@ -544,8 +550,7 @@ UITabWidget* App::createEditorWithTabWidget( Node* parent ) { tabWidget->setAllowDragAndDropTabs( true ); tabWidget->addEventListener( Event::OnTabSelected, [&]( const Event* event ) { UITabWidget* tabWidget = event->getNode()->asType(); - mCurEditor = tabWidget->getTabSelected()->getOwnedWidget()->asType(); - updateEditorState(); + setCurrentEditor( tabWidget->getTabSelected()->getOwnedWidget()->asType() ); } ); tabWidget->setTabTryCloseCallback( [&]( UITab* tab ) -> bool { tryTabClose( tab->getOwnedWidget()->asType() ); @@ -566,13 +571,13 @@ UITabWidget* App::createEditorWithTabWidget( Node* parent ) { UITabWidget* App::tabWidgetFromEditor( UICodeEditor* editor ) { if ( editor ) return ( (UITab*)editor->getData() )->getTabWidget(); - return NULL; + return nullptr; } UISplitter* App::splitterFromEditor( UICodeEditor* editor ) { if ( editor && editor->getParent()->getParent()->getParent()->isType( UI_TYPE_SPLITTER ) ) return editor->getParent()->getParent()->getParent()->asType(); - return NULL; + return nullptr; } void App::setAppTitle( const std::string& title ) { @@ -582,7 +587,7 @@ void App::setAppTitle( const std::string& title ) { bool App::loadFileFromPath( const std::string& path, UICodeEditor* codeEditor ) { if ( FileSystem::isDirectory( path ) ) return false; - if ( NULL == codeEditor ) + if ( nullptr == codeEditor ) codeEditor = mCurEditor; codeEditor->setColorScheme( mColorSchemes[mCurrentColorScheme] ); bool ret = codeEditor->loadFromFile( path ); @@ -590,20 +595,37 @@ bool App::loadFileFromPath( const std::string& path, UICodeEditor* codeEditor ) if ( codeEditor == mCurEditor ) updateCurrentFiletype(); removeUnusedTab( tabWidgetFromEditor( codeEditor ) ); + + auto found = std::find( mRecentFiles.begin(), mRecentFiles.end(), path ); + if ( found != mRecentFiles.end() ) + mRecentFiles.erase( found ); + mRecentFiles.insert( mRecentFiles.begin(), path ); + if ( mRecentFiles.size() > 10 ) + mRecentFiles.resize( 10 ); + updateRecentFiles(); return ret; } +void App::loadFileFromPathInNewTab( const std::string& path ) { + auto d = createCodeEditorInTabWidget( tabWidgetFromEditor( mCurEditor ) ); + UITabWidget* tabWidget = d.first->getTabWidget(); + UITab* addedTab = d.first; + loadFileFromPath( path, d.second ); + tabWidget->setTabSelected( addedTab ); +} + +void App::setCurrentEditor( UICodeEditor* editor ) { + mCurEditor = editor; + updateEditorState(); +} + void App::openFileDialog() { UIFileDialog* dialog = UIFileDialog::New(); dialog->setWinFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_MAXIMIZE_BUTTON | UI_WIN_MODAL ); dialog->setTitle( "Open File" ); dialog->setCloseShortcut( KEY_ESCAPE ); dialog->addEventListener( Event::OpenFile, [&]( const Event* event ) { - auto d = createCodeEditorInTabWidget( tabWidgetFromEditor( mCurEditor ) ); - UITabWidget* tabWidget = d.first->getTabWidget(); - UITab* addedTab = d.first; - loadFileFromPath( event->getNode()->asType()->getFullPath(), d.second ); - tabWidget->setTabSelected( addedTab ); + loadFileFromPathInNewTab( event->getNode()->asType()->getFullPath() ); } ); dialog->addEventListener( Event::OnWindowClose, [&]( const Event* ) { if ( mCurEditor && !SceneManager::instance()->isShootingDown() ) @@ -736,6 +758,54 @@ void App::runCommand( const std::string& command ) { } } +void App::loadConfig() { + std::string path( Sys::getConfigPath( "ecode" ) ); + if ( !FileSystem::fileExists( path ) ) + FileSystem::makeDir( path ); + FileSystem::dirPathAddSlashAtEnd( path ); + path += "config.cfg"; + mIni.loadFromFile( path ); + mIni.readFile(); + std::string recent = mIni.getValue( "files", "recentfiles", "" ); + mRecentFiles = String::split( recent, ';' ); + mCurrentColorScheme = mConfig.editor.colorScheme = + mIni.getValue( "editor", "colorscheme", "lite" ); + mConfig.editor.fontSize = mIni.getValueF( "editor", "font_size", 11 ); + mConfig.window.size.setWidth( mIni.getValueI( "window", "width", 1280 ) ); + mConfig.window.size.setHeight( mIni.getValueI( "window", "height", 720 ) ); + mConfig.window.maximized = mIni.getValueB( "window", "maximized", false ); + mConfig.window.pixelDensity = mIni.getValueF( "window", "pixeldensity" ); + mConfig.editor.showLineNumbers = mIni.getValueB( "editor", "show_line_numbers", true ); + mConfig.editor.showWhiteSpaces = mIni.getValueB( "editor", "show_white_spaces", true ); + mConfig.editor.highlightMatchingBracket = + mIni.getValueB( "editor", "highlight_matching_brackets", true ); + mConfig.editor.highlightCurrentLine = + mIni.getValueB( "editor", "highlight_current_line", true ); + mConfig.editor.horizontalScrollbar = mIni.getValueB( "editor", "horizontal_scrollbar", false ); + mConfig.ui.fontSize = mIni.getValueF( "ui", "font_size", 11 ); +} + +void App::saveConfig() { + mConfig.editor.colorScheme = mCurrentColorScheme; + mConfig.window.size = ( mWindow->getSize().asFloat() / mConfig.window.pixelDensity ).asInt(); + mConfig.window.maximized = mWindow->isMaximized(); + mIni.setValue( "editor", "colorscheme", mConfig.editor.colorScheme ); + mIni.setValueI( "window", "width", mConfig.window.size.getWidth() ); + mIni.setValueI( "window", "height", mConfig.window.size.getHeight() ); + mIni.setValueB( "window", "maximized", mConfig.window.maximized ); + mIni.setValueF( "window", "pixeldensity", mConfig.window.pixelDensity ); + mIni.setValue( "files", "recentfiles", String::join( mRecentFiles, ';' ) ); + mIni.setValueB( "editor", "show_line_numbers", mConfig.editor.showLineNumbers ); + mIni.setValueB( "editor", "show_white_spaces", mConfig.editor.showWhiteSpaces ); + mIni.setValueB( "editor", "highlight_matching_brackets", + mConfig.editor.highlightMatchingBracket ); + mIni.setValueB( "editor", "highlight_current_line", mConfig.editor.highlightCurrentLine ); + mIni.setValueB( "editor", "horizontal_scrollbar", mConfig.editor.horizontalScrollbar ); + mIni.setValueF( "editor", "font_size", mConfig.editor.fontSize ); + mIni.setValueF( "ui", "font_size", mConfig.ui.fontSize ); + mIni.writeFile(); +} + void App::initSearchBar() { auto addClickListener = [&]( UIWidget* widget, std::string cmd ) { widget->addEventListener( Event::MouseClick, [this, cmd]( const Event* event ) { @@ -824,7 +894,7 @@ void App::showFindView() { } void App::closeApp() { - if ( NULL == mMsgBox && onCloseRequestCallback( mWindow ) ) { + if ( nullptr == mMsgBox && onCloseRequestCallback( mWindow ) ) { mWindow->close(); } } @@ -892,23 +962,138 @@ void App::onTextDropped( String text ) { } App::~App() { + saveConfig(); eeSAFE_DELETE( mConsole ); } +void App::updateRecentFiles() { + UINode* node = nullptr; + if ( mSettingsMenu && ( node = mSettingsMenu->getItem( "Recent Files" ) ) ) { + UIMenuSubMenu* uiMenuSubMenu = static_cast( node ); + UIMenu* menu = uiMenuSubMenu->getSubMenu(); + uiMenuSubMenu->setEnabled( !mRecentFiles.empty() ); + menu->removeAll(); + menu->removeEventsOfType( Event::OnItemClicked ); + if ( mRecentFiles.empty() ) + return; + for ( auto file : mRecentFiles ) + menu->add( file ); + menu->addSeparator(); + menu->add( "Clear Menu" ); + menu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) { + if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) + return; + const String& txt = event->getNode()->asType()->getText(); + if ( txt != "Clear Menu" ) { + std::string path( txt.toUtf8() ); + if ( FileSystem::fileExists( path ) && !FileSystem::isDirectory( path ) ) { + loadFileFromPathInNewTab( path ); + } + } else { + mRecentFiles.clear(); + updateRecentFiles(); + } + } ); + } +} + +UIMenu* App::createViewMenu() { + UIPopUpMenu* menu = UIPopUpMenu::New(); + menu->addCheckBox( "Show Line Numbers" )->setActive( mConfig.editor.showLineNumbers ); + menu->addCheckBox( "Show White Space" )->setActive( mConfig.editor.showWhiteSpaces ); + menu->addCheckBox( "Highlight Matching Bracket" ) + ->setActive( mConfig.editor.highlightMatchingBracket ); + menu->addCheckBox( "Highlight Current Line" )->setActive( mConfig.editor.highlightCurrentLine ); + menu->addCheckBox( "Enable Horizontal ScrollBar" ) + ->setActive( mConfig.editor.horizontalScrollbar ); + menu->addSeparator(); + menu->add( "Split Left", findIcon( "split-horizontal" ), "Ctrl+Shift+J" ); + menu->add( "Split Right", findIcon( "split-horizontal" ), "Ctrl+Shift+L" ); + menu->add( "Split Top", findIcon( "split-vertical" ), "Ctrl+Shift+I" ); + menu->add( "Split Bottom", findIcon( "split-vertical" ), "Ctrl+Shift+K" ); + menu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) { + if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) + return; + UIMenuItem* item = event->getNode()->asType(); + if ( item->getText() == "Show Line Numbers" ) { + mConfig.editor.showLineNumbers = item->asType()->isActive(); + forEachEditor( [&]( UICodeEditor* editor ) { + editor->setShowLineNumber( mConfig.editor.showLineNumbers ); + } ); + } else if ( item->getText() == "Show White Space" ) { + mConfig.editor.showWhiteSpaces = item->asType()->isActive(); + forEachEditor( [&]( UICodeEditor* editor ) { + editor->setShowWhitespaces( mConfig.editor.showWhiteSpaces ); + } ); + } else if ( item->getText() == "Highlight Matching Bracket" ) { + mConfig.editor.highlightMatchingBracket = item->asType()->isActive(); + forEachEditor( [&]( UICodeEditor* editor ) { + editor->setHighlightMatchingBracket( mConfig.editor.highlightMatchingBracket ); + } ); + } else if ( item->getText() == "Highlight Current Line" ) { + mConfig.editor.highlightCurrentLine = item->asType()->isActive(); + forEachEditor( [&]( UICodeEditor* editor ) { + editor->setHighlightCurrentLine( mConfig.editor.highlightCurrentLine ); + } ); + } else if ( item->getText() == "Enable Horizontal ScrollBar" ) { + mConfig.editor.horizontalScrollbar = item->asType()->isActive(); + forEachEditor( [&]( UICodeEditor* editor ) { + editor->setHorizontalScrollBarEnabled( mConfig.editor.horizontalScrollbar ); + } ); + } else { + String text = String( event->getNode()->asType()->getText() ).toLower(); + String::replaceAll( text, " ", "-" ); + String::replaceAll( text, "/", "-" ); + runCommand( text ); + } + } ); + return menu; +} + +Drawable* App::findIcon( const std::string& name ) { + return mUISceneNode->findIcon( name ); +} + +UIMenu* App::createEditMenu() { + UIPopUpMenu* menu = UIPopUpMenu::New(); + menu->add( "Undo", findIcon( "undo" ), "Ctrl+Z" ); + menu->add( "Redo", findIcon( "redo" ), "Ctrl+Shift+Z" ); + menu->addSeparator(); + menu->add( "Cut", findIcon( "cut" ), "Ctrl+X" ); + menu->add( "Copy", findIcon( "copy" ), "Ctrl+C" ); + menu->add( "Paste", findIcon( "paste" ), "Ctrl+V" ); + menu->addSeparator(); + menu->add( "Select All", findIcon( "select-all" ), "Ctrl+A" ); + menu->addSeparator(); + menu->add( "Find/Replace", findIcon( "find-replace" ), "Ctrl+F" ); + menu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) { + if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) + return; + String text = String( event->getNode()->asType()->getText() ).toLower(); + String::replaceAll( text, " ", "-" ); + String::replaceAll( text, "/", "-" ); + runCommand( text ); + } ); + return menu; +} + void App::createSettingsMenu() { mSettingsMenu = UIPopUpMenu::New(); - mSettingsMenu->add( "New", mUISceneNode->findIcon( "document-new" ), "Ctrl+T" ); - mSettingsMenu->add( "Open...", mUISceneNode->findIcon( "document-open" ), "Ctrl+O" ); + mSettingsMenu->add( "New", findIcon( "document-new" ), "Ctrl+T" ); + mSettingsMenu->add( "Open...", findIcon( "document-open" ), "Ctrl+O" ); + mSettingsMenu->addSubMenu( "Recent Files", findIcon( "document-recent" ), UIPopUpMenu::New() ); mSettingsMenu->addSeparator(); - mSettingsMenu->add( "Save", mUISceneNode->findIcon( "document-save" ), "Ctrl+S" ); - mSettingsMenu->add( "Save as...", mUISceneNode->findIcon( "document-save-as" ) ); + mSettingsMenu->add( "Save", findIcon( "document-save" ), "Ctrl+S" ); + mSettingsMenu->add( "Save as...", findIcon( "document-save-as" ) ); mSettingsMenu->addSeparator(); - mSettingsMenu->addSubMenu( "Filetype", NULL, createFiletypeMenu() ); - mSettingsMenu->addSubMenu( "Color Scheme", NULL, createColorSchemeMenu() ); + mSettingsMenu->addSubMenu( "Edit", nullptr, createEditMenu() ); + mSettingsMenu->addSubMenu( "View", nullptr, createViewMenu() ); + mSettingsMenu->addSubMenu( "Filetype", nullptr, createFiletypeMenu() ); + mSettingsMenu->addSubMenu( "Color Scheme", nullptr, createColorSchemeMenu() ); mSettingsMenu->addSeparator(); - mSettingsMenu->add( "Close", mUISceneNode->findIcon( "document-close" ), "Ctrl+W" ); + mSettingsMenu->add( "Close", findIcon( "document-close" ), "Ctrl+W" ); mSettingsMenu->addSeparator(); - mSettingsMenu->add( "Quit", mUISceneNode->findIcon( "quit" ), "Ctrl+Q" ); + mSettingsMenu->add( "Quit", findIcon( "quit" ), "Ctrl+Q" ); mSettingsButton = mUISceneNode->find( "settings" ); mSettingsButton->addEventListener( Event::MouseClick, [&]( const Event* ) { Vector2f pos( mSettingsButton->getPixelsPosition() ); @@ -935,6 +1120,7 @@ void App::createSettingsMenu() { runCommand( "close-app" ); } } ); + updateRecentFiles(); } void App::setColorScheme( const std::string& name ) { @@ -996,14 +1182,21 @@ void App::updateCurrentFiletype() { } void App::updateEditorState() { - updateEditorTitle( mCurEditor ); - updateCurrentFiletype(); + if ( mCurEditor ) { + updateEditorTitle( mCurEditor ); + updateCurrentFiletype(); + } } void App::init( const std::string& file, const Float& pidelDensity ) { + loadConfig(); + DisplayManager* displayManager = Engine::instance()->getDisplayManager(); Display* currentDisplay = displayManager->getDisplayIndex( 0 ); - Float pixelDensity = pidelDensity > 0 ? pidelDensity : currentDisplay->getPixelDensity(); + mConfig.window.pixelDensity = + pidelDensity > 0 ? pidelDensity + : ( mConfig.window.pixelDensity > 0 ? mConfig.window.pixelDensity + : currentDisplay->getPixelDensity() ); displayManager->enableScreenSaver(); displayManager->enableMouseFocusClickThrough(); @@ -1012,11 +1205,15 @@ void App::init( const std::string& file, const Float& pidelDensity ) { std::string resPath( Sys::getProcessPath() ); mWindow = Engine::instance()->createWindow( - WindowSettings( 1280, 720, mWindowTitle, WindowStyle::Default, WindowBackend::Default, 32, - resPath + "assets/icon/ee.png", pixelDensity ), + WindowSettings( mConfig.window.size.getWidth(), mConfig.window.size.getHeight(), + mWindowTitle, WindowStyle::Default, WindowBackend::Default, 32, + resPath + "assets/icon/ee.png", mConfig.window.pixelDensity ), ContextSettings( true ) ); if ( mWindow->isOpen() ) { + if ( mConfig.window.maximized ) + mWindow->maximize(); + mWindow->setCloseRequestCallback( [&]( EE::Window::Window* win ) -> bool { return onCloseRequestCallback( win ); } ); @@ -1028,7 +1225,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { } } ); - PixelDensity::setPixelDensity( eemax( mWindow->getScale(), pixelDensity ) ); + PixelDensity::setPixelDensity( eemax( mWindow->getScale(), mConfig.window.pixelDensity ) ); mUISceneNode = UISceneNode::New(); @@ -1045,20 +1242,25 @@ void App::init( const std::string& file, const Float& pidelDensity ) { SceneManager::instance()->add( mUISceneNode ); mTheme = UITheme::load( "uitheme", "uitheme", "", font, resPath + "assets/ui/breeze.css" ); + mTheme->setDefaultFontSize( mConfig.ui.fontSize ); mUISceneNode->setStyleSheet( mTheme->getStyleSheet() ); mUISceneNode ->getUIThemeManager() //->setDefaultEffectsEnabled( true ) ->setDefaultTheme( mTheme ) ->setDefaultFont( font ) + ->setDefaultFontSize( mConfig.ui.fontSize ) ->add( mTheme ); auto colorSchemes = SyntaxColorScheme::loadFromFile( resPath + "assets/colorschemes/colorschemes.conf" ); if ( !colorSchemes.empty() ) { - mCurrentColorScheme = colorSchemes[0].getName(); for ( auto& colorScheme : colorSchemes ) mColorSchemes[colorScheme.getName()] = colorScheme; + mCurrentColorScheme = + mColorSchemes.find( mConfig.editor.colorScheme ) != mColorSchemes.end() + ? mConfig.editor.colorScheme + : colorSchemes[0].getName(); } else { mColorSchemes["default"] = SyntaxColorScheme::getDefault(); mCurrentColorScheme = "default"; @@ -1156,6 +1358,19 @@ void App::init( const std::string& file, const Float& pidelDensity ) { addIcon( "document-save-as", 0xf0b3, 12 ); addIcon( "document-close", 0xeb99, 12 ); addIcon( "quit", 0xeb97, 12 ); + addIcon( "undo", 0xea58, 12 ); + addIcon( "redo", 0xea5a, 12 ); + addIcon( "redo", 0xea5a, 12 ); + addIcon( "cut", 0xf0c1, 12 ); + addIcon( "copy", 0xecd5, 12 ); + addIcon( "paste", 0xeb91, 12 ); + addIcon( "split-horizontal", 0xf17a, 12 ); + addIcon( "split-vertical", 0xf17b, 12 ); + addIcon( "find-replace", 0xed2b, 12 ); + /*addIcon( "folder", 0xed54, 12 ); + addIcon( "folder-add", 0xed5a, 12 ); + addIcon( "file", 0xecc3, 12 ); + addIcon( "file-code", 0xecd1, 12 );*/ mUISceneNode->getUIIconThemeManager()->setCurrentTheme( iconTheme ); initSearchBar(); diff --git a/src/tools/codeeditor/codeeditor.hpp b/src/tools/codeeditor/codeeditor.hpp index f19bd5d19..3ade7ebe9 100644 --- a/src/tools/codeeditor/codeeditor.hpp +++ b/src/tools/codeeditor/codeeditor.hpp @@ -37,6 +37,26 @@ class UISearchBar : public UILinearLayout { class App { public: + struct Config { + struct { + Float pixelDensity{0}; + Sizei size{1280, 720}; + bool maximized{false}; + } window; + struct { + std::string colorScheme{"lite"}; + Float fontSize{11}; + bool showLineNumbers{true}; + bool showWhiteSpaces{true}; + bool highlightMatchingBracket{true}; + bool horizontalScrollbar{false}; + bool highlightCurrentLine{true}; + } editor; + struct { + Float fontSize{11}; + } ui; + }; + enum class SplitDirection { Left, Right, Top, Bottom }; ~App(); @@ -95,6 +115,14 @@ class App { void runCommand( const std::string& command ); + void loadConfig(); + + void saveConfig(); + + void loadFileFromPathInNewTab( const std::string& path ); + + void setCurrentEditor( UICodeEditor* editor ); + protected: EE::Window::Window* mWindow{NULL}; UISceneNode* mUISceneNode{NULL}; @@ -113,6 +141,9 @@ class App { UIPopUpMenu* mColorSchemeMenu; UIPopUpMenu* mFiletypeMenu; UITheme* mTheme; + IniFile mIni; + std::vector mRecentFiles; + Config mConfig; void onFileDropped( String file ); @@ -155,6 +186,16 @@ class App { void saveDoc(); void removeUnusedTab( UITabWidget* tabWidget ); + + void updateRecentFiles(); + + void forEachEditor( std::function run ); + + UIMenu* createViewMenu(); + + UIMenu* createEditMenu(); + + Drawable* findIcon( const std::string& name ); }; #endif // EE_TOOLS_CODEEDITOR_HPP