diff --git a/bin/assets/plugins/linters.json b/bin/assets/plugins/linters.json index b0348eafb..e6d269b05 100644 --- a/bin/assets/plugins/linters.json +++ b/bin/assets/plugins/linters.json @@ -65,7 +65,7 @@ "file_patterns": ["%.inl$", "%.cpp$", "%.hpp$", "%.cc$", "%.cxx$", "%.c++$", "%.hh$", "%.hxx$", "%.h++$", "%.objcpp$"], "warning_pattern": "$FILENAME:(%d+):(%d+):%s?([^%s]*)([^\n]*)", "warning_pattern_order": { "line": 1, "col": 2, "message": 4, "type": 3 }, - "command": "cppcheck --language=c++ --enable=all --template=gcc $FILENAME", + "command": "cppcheck --language=c++ --enable=all --template=gcc --inline-suppr $FILENAME", "url": "https://github.com/danmar/cppcheck" }, { diff --git a/include/eepp/scene/event.hpp b/include/eepp/scene/event.hpp index 3cf0f152b..e00e02857 100644 --- a/include/eepp/scene/event.hpp +++ b/include/eepp/scene/event.hpp @@ -13,6 +13,7 @@ class DropEvent; class TextEvent; class TextInputEvent; class WindowEvent; +class ItemValueEvent; class EE_API Event { public: @@ -96,6 +97,7 @@ class EE_API Event { OnTitleChange, OnWindowAdded, OnWindowRemoved, + OnItemValueChange, NoEvent = eeINDEX_NOT_FOUND }; @@ -121,6 +123,8 @@ class EE_API Event { const WindowEvent* asWindowEvent() const; + const ItemValueEvent* asItemValueEvent() const; + protected: friend class Node; Node* mNode; @@ -159,6 +163,16 @@ class EE_API WindowEvent : public Event { Node* window; }; +class EE_API ItemValueEvent : public Event { + public: + ItemValueEvent( Node* node, const Uint32& eventType, const Uint32& itemIndex ) : + Event( node, eventType ), itemIndex( itemIndex ) {} + const Uint32& getItemIndex() const { return itemIndex; } + + protected: + Uint32 itemIndex; +}; + }} // namespace EE::Scene #endif diff --git a/include/eepp/scene/node.hpp b/include/eepp/scene/node.hpp index 1bdec32fe..09404ea86 100644 --- a/include/eepp/scene/node.hpp +++ b/include/eepp/scene/node.hpp @@ -195,8 +195,8 @@ class EE_API Node : public Transformable { return addEventListener( eventType, callback ); } - Uint32 addMouseClickListener( const std::function& callback, - const MouseButton& button ); + Uint32 onClick( const std::function& callback, + const MouseButton& button = MouseButton::EE_BUTTON_LEFT ); void removeEventsOfType( const Uint32& eventType ); diff --git a/include/eepp/ui/uihelper.hpp b/include/eepp/ui/uihelper.hpp index c512f929b..c8f3341f6 100644 --- a/include/eepp/ui/uihelper.hpp +++ b/include/eepp/ui/uihelper.hpp @@ -40,7 +40,8 @@ enum UIFlag { UI_DRAG_VERTICAL = ( 1 << 23 ), UI_DRAG_HORIZONTAL = ( 1 << 24 ), UI_TAB_FOCUSABLE = ( 1 << 25 ), - UI_TOOLTIP_ENABLED = ( 1 << 26 ) + UI_TOOLTIP_ENABLED = ( 1 << 26 ), + UI_SCROLLABLE = ( 1 << 27 ), }; enum UINodeType { diff --git a/include/eepp/ui/uilistbox.hpp b/include/eepp/ui/uilistbox.hpp index 67146e729..fd3e85ef8 100644 --- a/include/eepp/ui/uilistbox.hpp +++ b/include/eepp/ui/uilistbox.hpp @@ -61,6 +61,8 @@ class EE_API UIListBox : public UITouchDraggableWidget { Uint32 getItemSelectedIndex() const; + bool hasSelection() const; + std::list getItemsSelectedIndex() const; std::list getItemsSelected(); @@ -108,6 +110,8 @@ class EE_API UIListBox : public UITouchDraggableWidget { Uint32 getMaxTextWidth() const; + void setItemText( const Uint32& index, const String& newText ); + protected: friend class UIListBoxItem; friend class UIItemContainer; diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index d4339fedd..80de1cefb 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -320,6 +320,8 @@ class EE_API UINode : public Node { Sizef fitMinMaxSizePx( const Sizef& size ) const; + bool isScrollable() const; + protected: Vector2f mDpPos; Sizef mDpSize; diff --git a/include/eepp/ui/uiscenenode.hpp b/include/eepp/ui/uiscenenode.hpp index 3ce1697d8..3eb0b2bcb 100644 --- a/include/eepp/ui/uiscenenode.hpp +++ b/include/eepp/ui/uiscenenode.hpp @@ -67,6 +67,9 @@ class EE_API UISceneNode : public SceneNode { UIWidget* loadLayoutFromString( const std::string& layoutString, Node* parent = NULL, const Uint32& marker = 0 ); + UIWidget* loadLayoutFromString( const char* layoutString, Node* parent = NULL, + const Uint32& marker = 0 ); + UIWidget* loadLayoutFromMemory( const void* buffer, Int32 bufferSize, Node* parent = NULL, const Uint32& marker = 0 ); diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 7748dc2a5..a3e4903f4 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -338,6 +338,10 @@ class EE_API UIWidget : public UINode { String getTranslatorString( const std::string& str ); String getTranslatorString( const std::string& str, const String& defaultValue ); + + String i18n( const std::string& str ); + + String i18n( const std::string& str, const String& defaultValue ); }; }} // namespace EE::UI diff --git a/src/eepp/scene/event.cpp b/src/eepp/scene/event.cpp index ce9fbee90..7b2ab43e2 100644 --- a/src/eepp/scene/event.cpp +++ b/src/eepp/scene/event.cpp @@ -45,4 +45,8 @@ const WindowEvent* Event::asWindowEvent() const { return static_cast( this ); } +const ItemValueEvent* Event::asItemValueEvent() const { + return static_cast( this ); +} + }} // namespace EE::Scene diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index f158ef352..3ee806242 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1125,7 +1125,7 @@ Uint32 Node::addEventListener( const Uint32& eventType, const EventCallback& cal return mNumCallBacks; } -Uint32 Node::addMouseClickListener( const std::function& callback, +Uint32 Node::onClick( const std::function& callback, const MouseButton& button ) { return addEventListener( Event::MouseClick, [callback, button]( const Event* event ) { if ( event->asMouseEvent()->getFlags() & ( EE_BUTTON_MASK( button ) ) ) { diff --git a/src/eepp/ui/tools/textureatlaseditor.cpp b/src/eepp/ui/tools/textureatlaseditor.cpp index 0ecaae121..125224d16 100644 --- a/src/eepp/ui/tools/textureatlaseditor.cpp +++ b/src/eepp/ui/tools/textureatlaseditor.cpp @@ -51,7 +51,7 @@ TextureAtlasEditor::TextureAtlasEditor( UIWindow* attachTo, const TGEditorCloseC mUIWindow->getContainer()->addClass( "appbackground" ); } - std::string layout = R"xml( + static const auto layout = R"xml( diff --git a/src/eepp/ui/tools/textureatlasnew.cpp b/src/eepp/ui/tools/textureatlasnew.cpp index 622a4f06a..5084e03b7 100644 --- a/src/eepp/ui/tools/textureatlasnew.cpp +++ b/src/eepp/ui/tools/textureatlasnew.cpp @@ -19,7 +19,7 @@ TextureAtlasNew::TextureAtlasNew( TGCreateCb NewTGCb ) : mUIWindow( NULL ), mNew cb::Make1( this, &TextureAtlasNew::windowClose ) ); mUIWindow->setTitle( "New Texture Atlas" ); - std::string layout = R"xml( + static const auto layout = R"xml( diff --git a/src/eepp/ui/tools/uicolorpicker.cpp b/src/eepp/ui/tools/uicolorpicker.cpp index cde13c6c9..6a0e8bd87 100644 --- a/src/eepp/ui/tools/uicolorpicker.cpp +++ b/src/eepp/ui/tools/uicolorpicker.cpp @@ -177,7 +177,7 @@ UIColorPicker::UIColorPicker( UIWindow* attachTo, const UIColorPicker::ColorPick mUIContainer = mUIWindow->getContainer(); } - std::string layout = R"xml( + static const auto layout = R"xml( diff --git a/src/eepp/ui/tools/uiwidgetinspector.cpp b/src/eepp/ui/tools/uiwidgetinspector.cpp index 81f06c274..e76cfce28 100644 --- a/src/eepp/ui/tools/uiwidgetinspector.cpp +++ b/src/eepp/ui/tools/uiwidgetinspector.cpp @@ -26,7 +26,7 @@ UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIc uiWin->setId( "widget-tree-view" ); uiWin->setMinWindowSize( 600, 400 ); uiWin->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_RESIZEABLE | UI_WIN_MAXIMIZE_BUTTON ); - UIWidget* cont = sceneNode->loadLayoutFromString( R"xml( + static const auto WIDGET_LAYOUT = R"xml( @@ -41,8 +41,8 @@ UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIc - )xml", - uiWin->getContainer() ); + )xml"; + UIWidget* cont = sceneNode->loadLayoutFromString( WIDGET_LAYOUT, uiWin->getContainer() ); UITreeView* widgetTree = cont->findByType( UI_TYPE_TREEVIEW ); widgetTree->setHeadersVisible( true ); widgetTree->setExpanderIconSize( menuIconSize ); diff --git a/src/eepp/ui/uiborderdrawable.cpp b/src/eepp/ui/uiborderdrawable.cpp index 4f834a5e3..52c4a118e 100644 --- a/src/eepp/ui/uiborderdrawable.cpp +++ b/src/eepp/ui/uiborderdrawable.cpp @@ -32,10 +32,7 @@ void UIBorderDrawable::draw( const Vector2f& position ) { } void UIBorderDrawable::draw( const Vector2f& position, const Sizef& size ) { - if ( mPosition != position ) { - mPosition = position; - mNeedsUpdate = true; - } + mPosition = position; if ( mSize != size ) { mSize = size; @@ -43,7 +40,6 @@ void UIBorderDrawable::draw( const Vector2f& position, const Sizef& size ) { } // TODO: Implement color update. - // TODO: Optimize position update. if ( mNeedsUpdate || mColorNeedsUpdate ) { update(); } @@ -55,7 +51,9 @@ void UIBorderDrawable::draw( const Vector2f& position, const Sizef& size ) { GLi->polygonSmooth( true ); mVertexBuffer->bind(); + GLi->translatef( mPosition.x, mPosition.y, 0 ); mVertexBuffer->draw(); + GLi->translatef( -mPosition.x, -mPosition.y, 0 ); mVertexBuffer->unbind(); if ( mSmooth && !isPolySmooth ) @@ -286,7 +284,7 @@ void UIBorderDrawable::update() { switch ( mBorderType ) { case BorderType::Outside: { - Vector2f pos( mPosition ); + Vector2f pos( Vector2f::Zero ); Sizef size( mSize ); if ( mBorders.top.width > 0 ) { @@ -310,11 +308,11 @@ void UIBorderDrawable::update() { break; } case BorderType::Inside: { - Borders::createBorders( mVertexBuffer, mBorders, mPosition, mSize ); + Borders::createBorders( mVertexBuffer, mBorders, Vector2f::Zero, mSize ); break; } case BorderType::Outline: { - Vector2f pos( mPosition ); + Vector2f pos( Vector2f::Zero ); Sizef size( mSize ); if ( mBorders.top.width > 0 ) { diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 7c4e8b755..366159051 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -122,7 +122,7 @@ UICodeEditor::UICodeEditor( const std::string& elementTag, const bool& autoRegis mKeyBindings( getUISceneNode()->getWindow()->getInput() ), mFindLongestLineWidthUpdateFrequency( Seconds( 1 ) ), mPreviewColor( Color::Transparent ) { - mFlags |= UI_TAB_STOP | UI_OWNS_CHILDS_POSITION; + mFlags |= UI_TAB_STOP | UI_OWNS_CHILDS_POSITION | UI_SCROLLABLE; setTextSelection( true ); setColorScheme( SyntaxColorScheme::getDefault() ); mVScrollBar = UIScrollBar::NewVertical(); diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp index 866751b32..b93dcf7ec 100644 --- a/src/eepp/ui/uiconsole.cpp +++ b/src/eepp/ui/uiconsole.cpp @@ -39,7 +39,7 @@ UIConsole::UIConsole( Font* font, const bool& makeDefaultCommands, const bool& a const unsigned int& maxLogLines ) : UIWidget( "console" ), mKeyBindings( getUISceneNode()->getWindow()->getInput() ) { setFlags( UI_AUTO_PADDING ); - mFlags |= UI_TAB_STOP; + mFlags |= UI_TAB_STOP | UI_SCROLLABLE; setClipType( ClipType::ContentBox ); setBackgroundColor( 0x201F1FEE ); diff --git a/src/eepp/ui/uidropdownlist.cpp b/src/eepp/ui/uidropdownlist.cpp index 7847231fe..4b07448d0 100644 --- a/src/eepp/ui/uidropdownlist.cpp +++ b/src/eepp/ui/uidropdownlist.cpp @@ -22,7 +22,7 @@ UIDropDownList::UIDropDownList( const std::string& tag ) : UITextInput( tag ), mListBox( NULL ), mFriendNode( NULL ) { mEnabledCreateContextMenu = false; setClipType( ClipType::ContentBox ); - setFlags( UI_AUTO_SIZE | UI_AUTO_PADDING ); + setFlags( UI_AUTO_SIZE | UI_AUTO_PADDING | UI_SCROLLABLE ); unsetFlags( UI_TEXT_SELECTION_ENABLED ); setAllowEditing( false ); @@ -48,6 +48,15 @@ UIDropDownList::UIDropDownList( const std::string& tag ) : mListBox->addEventListener( Event::KeyDown, cb::Make1( this, &UIDropDownList::onItemKeyDown ) ); mListBox->addEventListener( Event::OnClear, cb::Make1( this, &UIDropDownList::onWidgetClear ) ); mListBox->addEventListener( Event::OnClose, [&]( const Event* ) { mListBox = nullptr; } ); + mListBox->addEventListener( Event::OnSelectionChanged, [this]( auto ) { + if ( !mListBox->hasSelection() ) + mListBox->setSelected( 0 ); + sendCommonEvent( Event::OnSelectionChanged ); + } ); + mListBox->addEventListener( Event::OnItemValueChange, [this]( const Event* event ) { + if ( mListBox->getItemSelectedIndex() == event->asItemValueEvent()->getItemIndex() ) + setText( mListBox->getItemSelectedText() ); + } ); } UIDropDownList::~UIDropDownList() { @@ -264,6 +273,7 @@ void UIDropDownList::onItemSelected( const Event* ) { sendCommonEvent( Event::OnItemSelected ); sendCommonEvent( Event::OnValueChange ); + sendCommonEvent( Event::OnSelectionChanged ); } void UIDropDownList::show() { diff --git a/src/eepp/ui/uilistbox.cpp b/src/eepp/ui/uilistbox.cpp index 7d2571ec6..24c1e3746 100644 --- a/src/eepp/ui/uilistbox.cpp +++ b/src/eepp/ui/uilistbox.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -188,49 +189,31 @@ Uint32 UIListBox::removeListBoxItem( UIListBoxItem* Item ) { } void UIListBox::removeListBoxItems( std::vector ItemsIndex ) { - if ( ItemsIndex.size() && eeINDEX_NOT_FOUND != ItemsIndex[0] ) { - std::vector ItemsCpy; - mTexts.clear(); + if ( ItemsIndex.empty() || eeINDEX_NOT_FOUND == ItemsIndex[0] ) + return; - for ( Uint32 i = 0; i < mItems.size(); i++ ) { - bool erase = false; + size_t selectedSize = mSelected.size(); - for ( Uint32 z = 0; z < ItemsIndex.size(); z++ ) { - if ( ItemsIndex[z] == i ) { - for ( std::list::iterator it = mSelected.begin(); it != mSelected.end(); - ++it ) { - if ( *it == ItemsIndex[z] ) { - mSelected.erase( it ); - - break; - } - } - - ItemsIndex.erase( ItemsIndex.begin() + z ); - - erase = true; - - break; - } - } - - if ( !erase ) { - ItemsCpy.push_back( mItems[i] ); - mTexts.push_back( mItems[i]->getText() ); - } else if ( NULL != mItems[i] ) { - mItems[i]->close(); - mItems[i]->setVisible( false ); - mItems[i]->setEnabled( false ); - mItems[i] = NULL; - } + for ( Uint32 z = 0; z < ItemsIndex.size(); z++ ) { + auto idx = ItemsIndex[z]; + auto selIt = std::find( mSelected.begin(), mSelected.end(), idx ); + if ( selIt != mSelected.end() ) + mSelected.erase( selIt ); + if ( idx < mItems.size() && NULL != mItems[idx] ) { + mItems[idx]->close(); + mItems[idx]->setVisible( false ); + mItems[idx]->setEnabled( false ); } - - mItems = ItemsCpy; - - findMaxWidth(); - updateScroll(); - updateListBoxItemsSize(); + mItems.erase( mItems.begin() + idx ); + mTexts.erase( mTexts.begin() + idx ); } + + findMaxWidth(); + updateScroll(); + updateListBoxItemsSize(); + + if ( selectedSize != mSelected.size() ) + sendCommonEvent( Event::OnSelectionChanged ); } void UIListBox::clear() { @@ -244,6 +227,7 @@ void UIListBox::clear() { updateListBoxItemsSize(); sendCommonEvent( Event::OnClear ); + sendCommonEvent( Event::OnSelectionChanged ); } Uint32 UIListBox::removeListBoxItem( Uint32 ItemIndex ) { @@ -256,7 +240,7 @@ Uint32 UIListBox::getListBoxItemIndex( const String& Name ) { Uint32 size = (Uint32)mItems.size(); for ( Uint32 i = 0; i < size; i++ ) { - if ( Name == mItems[i]->getText() ) + if ( Name == mTexts[i] ) return i; } @@ -689,6 +673,7 @@ Uint32 UIListBox::onSelected() { NodeMessage tMsg( this, NodeMessage::Selected, 0 ); messagePost( &tMsg ); + sendCommonEvent( Event::OnSelectionChanged ); sendCommonEvent( Event::OnItemSelected ); return 1; @@ -706,9 +691,9 @@ bool UIListBox::isMultiSelect() const { } UIListBoxItem* UIListBox::getItem( const Uint32& Index ) const { - eeASSERT( Index < mItems.size() ) + eeASSERT( Index < mItems.size() ); - return mItems[Index]; + return mItems[Index]; } UIListBoxItem* UIListBox::getItemSelected() { @@ -729,6 +714,10 @@ Uint32 UIListBox::getItemSelectedIndex() const { return eeINDEX_NOT_FOUND; } +bool UIListBox::hasSelection() const { + return !mSelected.empty(); +} + String UIListBox::getItemSelectedText() const { String tstr; @@ -816,6 +805,9 @@ void UIListBox::setSelected( const String& Text ) { } void UIListBox::setSelected( Uint32 Index ) { + if ( std::find( mSelected.begin(), mSelected.end(), Index ) != mSelected.end() ) + return; + if ( Index < mItems.size() ) { if ( isMultiSelect() ) { for ( std::list::iterator it = mSelected.begin(); it != mSelected.end(); @@ -839,6 +831,7 @@ void UIListBox::setSelected( Uint32 Index ) { mItems[Index]->select(); } else { updateScroll(); + onSelected(); } } } @@ -1072,6 +1065,16 @@ Uint32 UIListBox::getMaxTextWidth() const { return mMaxTextWidth; } +void UIListBox::setItemText( const Uint32& index, const String& newText ) { + if ( index < mTexts.size() ) { + mTexts[index] = newText; + if ( nullptr != mItems[index] ) + mItems[index]->setText( newText ); + ItemValueEvent event( this, Event::OnItemValueChange, index ); + sendEvent( &event ); + } +} + bool UIListBox::applyProperty( const StyleSheetProperty& attribute ) { if ( !checkPropertyDefinition( attribute ) ) return false; diff --git a/src/eepp/ui/uilistboxitem.cpp b/src/eepp/ui/uilistboxitem.cpp index 5f5b3686c..bdb8afe5c 100644 --- a/src/eepp/ui/uilistboxitem.cpp +++ b/src/eepp/ui/uilistboxitem.cpp @@ -97,6 +97,7 @@ void UIListBoxItem::select() { mNodeFlags &= ~NODE_FLAG_SELECTED; LBParent->mSelected.remove( LBParent->getItemIndex( this ) ); + LBParent->sendCommonEvent( Event::OnSelectionChanged ); } } else { pushState( UIState::StateSelected ); @@ -113,6 +114,8 @@ void UIListBoxItem::select() { if ( !wasSelected ) { LBParent->onSelected(); + } else { + LBParent->sendCommonEvent( Event::OnSelectionChanged ); } } } diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 18de2effb..fd768f49d 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -455,6 +455,10 @@ Sizef UINode::fitMinMaxSizePx( const Sizef& size ) const { return s; } +bool UINode::isScrollable() const { + return 0 != ( mFlags & UI_SCROLLABLE ); +} + Sizef UINode::fitMinMaxSizeDp( const Sizef& size ) const { Sizef s( size ); diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index 108f164c3..10f0466d2 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -445,15 +445,15 @@ UIWidget* UISceneNode::loadLayoutFromFile( const std::string& layoutPath, Node* return NULL; } -UIWidget* UISceneNode::loadLayoutFromString( const std::string& layoutString, Node* parent, +UIWidget* UISceneNode::loadLayoutFromString( const char* layoutString, Node* parent, const Uint32& marker ) { pugi::xml_document doc; - pugi::xml_parse_result result = doc.load_string( layoutString.c_str() ); + pugi::xml_parse_result result = doc.load_string( layoutString ); if ( result ) { return loadLayoutNodes( doc.first_child(), NULL != parent ? parent : this, marker ); } else { - Log::error( "Couldn't load UI Layout from string: %s", layoutString.c_str() ); + Log::error( "Couldn't load UI Layout from string: %s", layoutString ); Log::error( "Error description: %s", result.description() ); Log::error( "Error offset: %d", result.offset ); } @@ -461,6 +461,11 @@ UIWidget* UISceneNode::loadLayoutFromString( const std::string& layoutString, No return NULL; } +UIWidget* UISceneNode::loadLayoutFromString( const std::string& layoutString, Node* parent, + const Uint32& marker ) { + return loadLayoutFromString( layoutString.c_str(), parent, marker ); +} + UIWidget* UISceneNode::loadLayoutFromMemory( const void* buffer, Int32 bufferSize, Node* parent, const Uint32& marker ) { pugi::xml_document doc; diff --git a/src/eepp/ui/uiscrollablewidget.cpp b/src/eepp/ui/uiscrollablewidget.cpp index 66392e970..b4eef3373 100644 --- a/src/eepp/ui/uiscrollablewidget.cpp +++ b/src/eepp/ui/uiscrollablewidget.cpp @@ -13,7 +13,7 @@ UIScrollableWidget::UIScrollableWidget( const std::string& tag ) : mHScroll( UIScrollBar::NewHorizontal() ), mSizeChangeCb( 0 ), mPosChangeCb( 0 ) { - mFlags |= UI_OWNS_CHILDS_POSITION; + mFlags |= UI_OWNS_CHILDS_POSITION | UI_SCROLLABLE; mVScroll->setParent( this ); mHScroll->setParent( this ); diff --git a/src/eepp/ui/uiscrollview.cpp b/src/eepp/ui/uiscrollview.cpp index 73ca29309..368ed526e 100644 --- a/src/eepp/ui/uiscrollview.cpp +++ b/src/eepp/ui/uiscrollview.cpp @@ -19,7 +19,7 @@ UIScrollView::UIScrollView() : mScrollView( NULL ), mSizeChangeCb( 0 ), mPosChangeCb( 0 ) { - mFlags |= UI_OWNS_CHILDS_POSITION; + mFlags |= UI_OWNS_CHILDS_POSITION | UI_SCROLLABLE; enableReportSizeChangeToChilds(); mVScroll->setParent( this ); @@ -349,7 +349,9 @@ bool UIScrollView::applyProperty( const StyleSheetProperty& attribute ) { Uint32 UIScrollView::onMessage( const NodeMessage* Msg ) { switch ( Msg->getMsg() ) { case NodeMessage::MouseUp: { - if ( mVScroll->isEnabled() && 0 != mScrollView->getSize().getHeight() ) { + if ( mVScroll->isEnabled() && 0 != mScrollView->getSize().getHeight() && + isTouchOverAllowedChilds() && Msg->getSender()->isUINode() && + !Msg->getSender()->asType()->isScrollable() ) { if ( Msg->getFlags() & EE_BUTTON_WUMASK ) { mVScroll->setValue( mVScroll->getValue() - mVScroll->getClickStep() ); return 1; diff --git a/src/eepp/ui/uislider.cpp b/src/eepp/ui/uislider.cpp index dda996087..673919ce6 100644 --- a/src/eepp/ui/uislider.cpp +++ b/src/eepp/ui/uislider.cpp @@ -45,6 +45,7 @@ UISlider::UISlider( const std::string& tag, const UIOrientation& orientation ) : mClickStep( 0.1f ), mPageStep( 0 ), mOnPosChange( false ) { + mFlags |= UI_SCROLLABLE; if ( UIOrientation::Horizontal == mOrientation ) { mBackSlider = UIWidget::NewWithTag( mTag + "::hback" ); diff --git a/src/eepp/ui/uispinbox.cpp b/src/eepp/ui/uispinbox.cpp index 379031283..15d5b2cdb 100644 --- a/src/eepp/ui/uispinbox.cpp +++ b/src/eepp/ui/uispinbox.cpp @@ -17,6 +17,7 @@ UISpinBox::UISpinBox() : mValue( 0 ), mClickStep( 1.f ), mModifyingVal( false ) { + mFlags |= UI_SCROLLABLE; mInput = UITextInput::NewWithTag( "spinbox::input" ); mInput->setVisible( true ); mInput->setEnabled( true ); diff --git a/src/eepp/ui/uitabwidget.cpp b/src/eepp/ui/uitabwidget.cpp index 5173a3827..6ec4abbb5 100644 --- a/src/eepp/ui/uitabwidget.cpp +++ b/src/eepp/ui/uitabwidget.cpp @@ -26,6 +26,7 @@ UITabWidget::UITabWidget() : mAllowSwitchTabsInEmptySpaces( false ), mDroppableHoveringColorWasSet( false ), mTabVerticalDragResistance( PixelDensity::dpToPx( 64 ) ) { + mFlags |= UI_SCROLLABLE; setHorizontalAlign( UI_HALIGN_CENTER ); setClipType( ClipType::ContentBox ); diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index 490ce21a1..9d654b153 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -410,6 +410,7 @@ void UITextView::onSizeChange() { void UITextView::onTextChanged() { sendCommonEvent( Event::OnTextChanged ); + sendCommonEvent( Event::OnValueChange ); invalidateDraw(); } @@ -841,7 +842,7 @@ UIAnchor* UIAnchor::New() { } UIAnchor::UIAnchor() : UITextView( "anchor" ) { - addMouseClickListener( + onClick( [this]( const MouseEvent* ) { if ( !mHref.empty() ) Engine::instance()->openURI( mHref ); diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 9e4244f33..32ae14712 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -1939,6 +1939,14 @@ String UIWidget::getTranslatorString( const std::string& str, const String& defa : defaultValue; } +String UIWidget::i18n( const std::string& str ) { + return getTranslatorString( str ); +} + +String UIWidget::i18n( const std::string& str, const String& defaultValue ) { + return getTranslatorString( str, defaultValue ); +} + UIWidget* UIWidget::getPrevTabWidget() const { UIWidget* widget = getPrevWidget(); if ( widget ) { diff --git a/src/examples/ui_hello_world/ui_hello_world.cpp b/src/examples/ui_hello_world/ui_hello_world.cpp index 715d7e75a..7d469d2da 100644 --- a/src/examples/ui_hello_world/ui_hello_world.cpp +++ b/src/examples/ui_hello_world/ui_hello_world.cpp @@ -58,7 +58,7 @@ EE_MAIN_FUNC int main( int, char** ) { SceneManager::instance()->add( uiSceneNode ); // Create a very simple Hello World with a TextView and a PushButton. - std::string layout = R"xml( + static const char* layout = R"xml( diff --git a/src/modules/eterm/src/eterm/ui/uiterminal.cpp b/src/modules/eterm/src/eterm/ui/uiterminal.cpp index c35e9ae35..336f4f915 100644 --- a/src/modules/eterm/src/eterm/ui/uiterminal.cpp +++ b/src/modules/eterm/src/eterm/ui/uiterminal.cpp @@ -50,7 +50,7 @@ UITerminal::UITerminal( const std::shared_ptr& terminalDisplay mKeyBindings( getUISceneNode()->getWindow()->getInput() ), mVScroll( UIScrollBar::NewVertical() ), mTerm( terminalDisplay ) { - mFlags |= UI_TAB_STOP; + mFlags |= UI_TAB_STOP | UI_SCROLLABLE; if ( !terminalDisplay ) return; mTerm->pushEventCallback( [&]( const TerminalDisplay::Event& event ) { diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index cb6226524..903a4d7b6 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1864,7 +1864,7 @@ void App::createDocAlert( UICodeEditor* editor ) { if ( docAlert ) return; - const std::string& msg = R"xml( + const auto msg = R"xml( combineStyleSheet( panelUI, false ); - const std::string baseUI = R"html( + const auto baseUI = R"html( @@ -605,10 +601,7 @@ void ProjectBuildManager::buildSidePanelTab() { - - - - + @@ -633,10 +626,10 @@ void ProjectBuildManager::updateSidePanelTab() { String first = mConfig.buildName; std::vector buildNamesItems; - for ( const auto& build : mBuilds ) { - buildNamesItems.push_back( build.first ); + for ( const auto& tbuild : mBuilds ) { + buildNamesItems.push_back( tbuild.first ); if ( first.empty() ) - first = build.first; + first = tbuild.first; } buildList->getListBox()->addListBoxItems( buildNamesItems ); @@ -669,56 +662,62 @@ void ProjectBuildManager::updateSidePanelTab() { cleanButton->setEnabled( !mConfig.buildName.empty() && hasBuild( mConfig.buildName ) && hasCleanCommands( mConfig.buildName ) ); - buildButton->addMouseClickListener( - [this]( const Event* ) { - if ( isBuilding() ) { - cancelBuild(); - } else { - buildCurrentConfig( mApp->getStatusBuildOutputController() ); - } - }, - MouseButton::EE_BUTTON_LEFT ); + buildButton->onClick( [this]( auto ) { + if ( isBuilding() ) { + cancelBuild(); + } else { + buildCurrentConfig( mApp->getStatusBuildOutputController() ); + } + } ); - cleanButton->addMouseClickListener( - [this]( const Event* ) { - if ( isBuilding() ) { - cancelBuild(); - } else { - cleanCurrentConfig( mApp->getStatusBuildOutputController() ); - } - }, - MouseButton::EE_BUTTON_LEFT ); + cleanButton->onClick( [this]( auto ) { + if ( isBuilding() ) { + cancelBuild(); + } else { + cleanCurrentConfig( mApp->getStatusBuildOutputController() ); + } + } ); - buildAdd->addMouseClickListener( - [this]( const Event* ) { - mNewBuild = ProjectBuild( mApp->i18n( "new_name", "new_name" ), mProjectRoot ); - auto ret = mApp->getSplitter()->createWidget( - UIBuildSettings::New( mNewBuild, mConfig ), - mApp->i18n( "build_settings", "Build Settings" ) ); - ret.first->setIcon( mApp->findIcon( "hammer" ) ); - }, - MouseButton::EE_BUTTON_LEFT ); + buildAdd->onClick( [this, buildTab]( auto ) { + mNewBuild = ProjectBuild( mApp->i18n( "new_name", "new_name" ), mProjectRoot ); + UIWidget* widget = nullptr; + if ( ( widget = buildTab->getUISceneNode()->getRoot()->querySelector( + "#build_settings_new_name" ) ) ) { + widget->asType()->select(); + return; + } + auto ret = + mApp->getSplitter()->createWidget( UIBuildSettings::New( mNewBuild, mConfig ), + mApp->i18n( "build_settings", "Build Settings" ) ); + ret.second->asType()->setTab( ret.first ); + ret.first->setIcon( mApp->findIcon( "hammer" ) ); + } ); - buildEdit->addMouseClickListener( - [this]( const Event* ) { - if ( !mConfig.buildName.empty() ) { - auto build = mBuilds.find( mConfig.buildName ); - if ( build != mBuilds.end() ) { - auto ret = mApp->getSplitter()->createWidget( - UIBuildSettings::New( build->second, mConfig ), - mApp->i18n( "build_settings", "Build Settings" ) ); - ret.first->setIcon( mApp->findIcon( "hammer" ) ); + buildEdit->onClick( [this, buildTab]( auto ) { + if ( !mConfig.buildName.empty() ) { + auto build = mBuilds.find( mConfig.buildName ); + if ( build != mBuilds.end() ) { + UIWidget* widget = nullptr; + if ( ( widget = buildTab->getUISceneNode()->getRoot()->querySelector( + "#build_settings_" + mConfig.buildName ) ) ) { + widget->asType()->select(); + return; } + auto ret = mApp->getSplitter()->createWidget( + UIBuildSettings::New( build->second, mConfig ), + mApp->i18n( "build_settings", "Build Settings" ) ); + ret.second->asType()->setTab( ret.first ); + ret.first->setIcon( mApp->findIcon( "hammer" ) ); } - }, - MouseButton::EE_BUTTON_LEFT ); + } + } ); } void ProjectBuildManager::updateBuildType() { UIWidget* buildTab = mTab->getOwnedWidget()->find( "build_tab" ); UIDropDownList* buildList = buildTab->find( "build_list" ); UIDropDownList* buildTypeList = buildTab->find( "build_type_list" ); - UIPushButton* buildTypeAdd = buildTab->find( "build_type_add" ); + // UIPushButton* buildTypeAdd = buildTab->find( "build_type_add" ); buildTypeList->getListBox()->clear(); @@ -741,7 +740,7 @@ void ProjectBuildManager::updateBuildType() { } } buildTypeList->setEnabled( !buildTypeList->getListBox()->isEmpty() ); - buildTypeAdd->setEnabled( !mConfig.buildName.empty() ); + // buildTypeAdd->setEnabled( !mConfig.buildName.empty() ); buildTypeList->removeEventsOfType( Event::OnItemSelected ); buildTypeList->addEventListener( Event::OnItemSelected, [this, buildTypeList]( const Event* ) { @@ -755,8 +754,14 @@ std::map ProjectBuildOutputParser::getPre return presets; } +bool ProjectBuildOutputParser::existsPreset( const std::string& name ) { + auto presets = getPresets(); + return presets.find( name ) != presets.end(); +} + ProjectBuildOutputParser ProjectBuildOutputParser::getGeneric() { ProjectBuildOutputParser parser; + parser.mConfig.reserve( 6 ); ProjectBuildOutputParserConfig cfg; cfg.pattern = "([^:]+):(%d+):(%d+):%s?[%w%s]*error:%s?(.*)"; @@ -767,11 +772,28 @@ ProjectBuildOutputParser ProjectBuildOutputParser::getGeneric() { cfg.type = ProjectOutputParserTypes::Error; parser.mConfig.push_back( cfg ); + cfg.pattern = "([^:]+):(%d+):%s?[%w%s]*error:%s?(.*)"; + cfg.patternOrder.col = 0; + cfg.type = ProjectOutputParserTypes::Error; + parser.mConfig.push_back( cfg ); + cfg.pattern = "([^:]+):(%d+):(%d+):%s?[%w%s]*warning:%s?(.*)"; + cfg.patternOrder.col = 3; + cfg.type = ProjectOutputParserTypes::Warning; + parser.mConfig.push_back( cfg ); + + cfg.pattern = "([^:]+):(%d+):%s?[%w%s]*warning:%s?(.*)"; + cfg.patternOrder.col = 0; cfg.type = ProjectOutputParserTypes::Warning; parser.mConfig.push_back( cfg ); cfg.pattern = "([^:]+):(%d+):(%d+):%s?[%w%s]*notice:%s?(.*)"; + cfg.patternOrder.col = 3; + cfg.type = ProjectOutputParserTypes::Notice; + parser.mConfig.emplace_back( cfg ); + + cfg.pattern = "([^:]+):(%d+):%s?[%w%s]*notice:%s?(.*)"; + cfg.patternOrder.col = 0; cfg.type = ProjectOutputParserTypes::Notice; parser.mConfig.emplace_back( cfg ); diff --git a/src/tools/ecode/projectbuild.hpp b/src/tools/ecode/projectbuild.hpp index da6bcfe90..c9e6ad6d2 100644 --- a/src/tools/ecode/projectbuild.hpp +++ b/src/tools/ecode/projectbuild.hpp @@ -110,16 +110,27 @@ class ProjectBuildOutputParser { public: static std::map getPresets(); + static bool existsPreset( const std::string& name ); + static ProjectBuildOutputParser getGeneric(); + const std::vector& getPresetConfig() const { + return mPresetConfig; + } + const std::vector& getConfig() const { return mConfig; } bool useRelativeFilePaths() const { return mRelativeFilePaths; } + const std::string& getPreset() const { return mPreset; } + protected: friend class ProjectBuildManager; + friend class UIBuildSettings; bool mRelativeFilePaths{ true }; + std::string mPreset; + std::vector mPresetConfig; std::vector mConfig; }; diff --git a/src/tools/ecode/statusbuildoutputcontroller.cpp b/src/tools/ecode/statusbuildoutputcontroller.cpp index 11b45b36a..97e236637 100644 --- a/src/tools/ecode/statusbuildoutputcontroller.cpp +++ b/src/tools/ecode/statusbuildoutputcontroller.cpp @@ -105,9 +105,13 @@ void StatusBuildOutputController::runBuild( const std::string& buildName, std::vector patterns; - for ( const auto& parser : outputParser.getConfig() ) { - SyntaxPattern ptn( { parser.pattern }, getProjectOutputParserTypeToString( parser.type ) ); - patterns.emplace_back( std::move( ptn ) ); + auto configs = { outputParser.getPresetConfig(), outputParser.getConfig() }; + for ( const auto& config : configs ) { + for ( const auto& parser : config ) { + SyntaxPattern ptn( { parser.pattern }, + getProjectOutputParserTypeToString( parser.type ) ); + patterns.emplace_back( std::move( ptn ) ); + } } patterns.emplace_back( diff --git a/src/tools/ecode/terminalmanager.cpp b/src/tools/ecode/terminalmanager.cpp index ed115230d..521235381 100644 --- a/src/tools/ecode/terminalmanager.cpp +++ b/src/tools/ecode/terminalmanager.cpp @@ -95,7 +95,7 @@ void TerminalManager::setUseFrameBuffer( bool useFrameBuffer ) { } void TerminalManager::configureTerminalShell() { - const std::string layout( R"xml( + static const auto layout( R"xml( @@ -153,11 +153,10 @@ void TerminalManager::configureTerminalShell() { shellCombo->getListBox()->getVerticalScrollBar()->setClickStep( shellCombo->getDropDownList()->getMaxNumVisibleItems() / (Float)found.size() ); ok->setFocus(); - ok->addMouseClickListener( + ok->onClick( [&, window, shellCombo]( const MouseEvent* ) { setShellFn( mApp, window, shellCombo ); }, MouseButton::EE_BUTTON_LEFT ); - cancel->addMouseClickListener( [window]( const MouseEvent* ) { window->closeWindow(); }, - EE_BUTTON_LEFT ); + cancel->onClick( [window]( const MouseEvent* ) { window->closeWindow(); }, EE_BUTTON_LEFT ); window->on( Event::KeyDown, [window]( const Event* event ) { if ( event->asKeyEvent()->getKeyCode() == KEY_ESCAPE ) window->closeWindow(); diff --git a/src/tools/ecode/uibuildsettings.cpp b/src/tools/ecode/uibuildsettings.cpp index 4aa9a224b..f665224b9 100644 --- a/src/tools/ecode/uibuildsettings.cpp +++ b/src/tools/ecode/uibuildsettings.cpp @@ -1,4 +1,5 @@ #include "uibuildsettings.hpp" +#include #include #include #include @@ -12,13 +13,38 @@ namespace ecode { class UIBuildStep : public UILinearLayout { public: static UIBuildStep* New( bool isBuildStep, UIBuildSettings* buildSettings, size_t stepNum, - ProjectBuildStep& buildStep ) { + ProjectBuildStep* buildStep ) { return eeNew( UIBuildStep, ( isBuildStep, buildSettings, stepNum, buildStep ) ); } + void clearBindings() { mDataBindHolder.clear(); } + + void updateStep( size_t stepNum, ProjectBuildStep* buildStep ) { + clearBindings(); + + removeClass( String::toString( mStepNum ) ); + mStepNum = stepNum; + mStep = buildStep; + addClass( String::toString( mStepNum ) ); + + findByClass( "step_name" ) + ->setText( String::format( mBuildSettings->getUISceneNode() + ->i18n( "build_step_num", "Step %u: %s" ) + .toUtf8() + .c_str(), + mStepNum + 1, mStep->cmd.c_str() ) ); + + mDataBindHolder += + UIDataBindBool::New( &mStep->enabled, findByClass( "enabled_checkbox" ) ); + auto placeholder = UIDataBindString::New( &mStep->cmd, findByClass( "input_cmd" ) ); + mDataBindHolder += UIDataBindString::New( &mStep->args, findByClass( "input_args" ) ); + mDataBindHolder += + UIDataBindString::New( &mStep->workingDir, findByClass( "input_working_dir" ) ); + } + protected: UIBuildStep( bool isBuildStep, UIBuildSettings* buildSettings, size_t stepNum, - ProjectBuildStep& buildStep ) : + ProjectBuildStep* buildStep ) : UILinearLayout( "buildstep", UIOrientation::Vertical ), mIsBuildStep( isBuildStep ), mBuildSettings( buildSettings ), @@ -26,6 +52,7 @@ class UIBuildStep : public UILinearLayout { mStep( buildStep ) { setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ); addClass( "build_step" ); + addClass( String::toString( stepNum ) ); static const auto BUILD_STEP_XML = R"xml( @@ -55,38 +82,42 @@ class UIBuildStep : public UILinearLayout { )xml"; getUISceneNode()->loadLayoutFromString( BUILD_STEP_XML, this ); - findByClass( "step_name" ) - ->setText( String::format( mBuildSettings->getUISceneNode() - ->i18n( "build_step_num", "Step %u" ) - .toUtf8() - .c_str(), - stepNum + 1 ) ); - mDataBindHolder += UIDataBindBool::New( &mStep.enabled, findByClass( "enabled_checkbox" ) ); - mDataBindHolder += UIDataBindString::New( &mStep.cmd, findByClass( "input_cmd" ) ); - mDataBindHolder += UIDataBindString::New( &mStep.args, findByClass( "input_args" ) ); - mDataBindHolder += - UIDataBindString::New( &mStep.workingDir, findByClass( "input_working_dir" ) ); - findByClass( "details_but" ) - ->addMouseClickListener( - [this]( const MouseEvent* event ) { - auto me = event->getNode()->asType(); - findByClass( "details" )->setVisible( me->hasClass( "contracted" ) ); - me->toggleClass( "contracted" ); - }, - MouseButton::EE_BUTTON_LEFT ); + + findByClass( "details_but" )->onClick( [this]( const MouseEvent* event ) { + auto me = event->getNode()->asType(); + findByClass( "details" )->setVisible( me->hasClass( "contracted" ) ); + me->toggleClass( "contracted" ); + } ); + + findByClass( "move_down" )->onClick( [this]( auto ) { + mBuildSettings->moveStepDown( mStepNum, !mIsBuildStep ); + } ); + + findByClass( "move_up" )->onClick( [this]( auto ) { + mBuildSettings->moveStepUp( mStepNum, !mIsBuildStep ); + } ); + + findByClass( "remove_item" )->onClick( [this]( auto ) { + mBuildSettings->deleteStep( mStepNum, !mIsBuildStep ); + } ); + + updateStep( mStepNum, mStep ); } bool mIsBuildStep{ true }; UIBuildSettings* mBuildSettings{ nullptr }; size_t mStepNum{ 0 }; - ProjectBuildStep& mStep; + ProjectBuildStep* mStep; UIDataBindHolder mDataBindHolder; }; static const auto SETTINGS_PANEL_XML = R"xml( - + + + + @@ -105,13 +136,13 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + - + @@ -139,7 +170,7 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + generic @@ -172,10 +203,26 @@ UIBuildSettings* UIBuildSettings::New( ProjectBuild& build, ProjectBuildConfigur } UIBuildSettings::UIBuildSettings( ProjectBuild& build, ProjectBuildConfiguration& config ) : - mBuild( build ), mConfig( config ) { + mBuild( build ), mConfig( config ), mOldName( mBuild.getName() ) { mUISceneNode->loadLayoutFromString( SETTINGS_PANEL_XML, this, String::hash( "build_settings" ) ); - mDataBindHolder += UIDataBindString::New( &mBuild.mName, find( "build_name" ) ); + auto buildNameInput = find( "build_name" ); + mDataBindHolder += UIDataBindString::New( &mBuild.mName, buildNameInput ); + + auto panelBuildNameDDL = getUISceneNode() + ->getRoot() + ->querySelector( " #build_tab #build_list" ) + ->asType(); + + buildNameInput->on( Event::OnValueChange, [this, panelBuildNameDDL]( auto ) { + refreshTab(); + if ( panelBuildNameDDL ) { + auto idx = panelBuildNameDDL->getListBox()->getItemIndex( mOldName ); + if ( idx != eeINDEX_NOT_FOUND ) + panelBuildNameDDL->getListBox()->setItemText( idx, mBuild.getName() ); + } + mOldName = mBuild.getName(); + } ); auto oses = find( "os_select" )->querySelectorAll( "CheckBox" ); for ( const auto os : oses ) { @@ -192,34 +239,60 @@ UIBuildSettings::UIBuildSettings( ProjectBuild& build, ProjectBuildConfiguration auto buildStepsParent = find( "build_steps_cont" ); for ( size_t step = 0; step < mBuild.mBuild.size(); ++step ) { - auto bs = UIBuildStep::New( true, this, step, mBuild.mBuild[step] ); + auto bs = UIBuildStep::New( true, this, step, &mBuild.mBuild[step] ); bs->setParent( buildStepsParent ); } + find( "add_build_step" )->onClick( [this, buildStepsParent]( const Event* ) { + mBuild.mBuild.push_back( {} ); + auto step = mBuild.mBuild.size() - 1; + UIBuildStep::New( true, this, step, &mBuild.mBuild[step] )->setParent( buildStepsParent ); + } ); + auto buildCleanStepsParent = find( "build_clean_steps_cont" ); for ( size_t step = 0; step < mBuild.mClean.size(); ++step ) { - auto bs = UIBuildStep::New( false, this, step, mBuild.mClean[step] ); - bs->setParent( buildCleanStepsParent ); + UIBuildStep::New( false, this, step, &mBuild.mClean[step] ) + ->setParent( buildCleanStepsParent ); } + find( "add_clean_step" )->onClick( [this, buildCleanStepsParent]( const Event* ) { + mBuild.mClean.push_back( {} ); + auto step = mBuild.mClean.size() - 1; + UIBuildStep::New( false, this, step, &mBuild.mClean[step] ) + ->setParent( buildCleanStepsParent ); + } ); + auto buildTypeDropDown = find( "build_type_list" ); + auto panelBuildTypeDDL = getUISceneNode() + ->getRoot() + ->querySelector( " #build_tab #build_type_list" ) + ->asType(); + std::vector buildTypes; for ( const auto& type : mBuild.mBuildTypes ) buildTypes.push_back( type ); buildTypeDropDown->getListBox()->addListBoxItems( buildTypes ); buildTypeDropDown->getListBox()->setSelected( mConfig.buildType ); - buildTypeDropDown->on( Event::OnItemSelected, [this, buildTypeDropDown]( const Event* ) { - mConfig.buildType = buildTypeDropDown->getListBox()->getItemSelectedText().toUtf8(); - } ); + buildTypeDropDown->on( + Event::OnItemSelected, [this, buildTypeDropDown, panelBuildTypeDDL]( const Event* ) { + mConfig.buildType = buildTypeDropDown->getListBox()->getItemSelectedText().toUtf8(); + if ( panelBuildTypeDDL ) + panelBuildTypeDDL->getListBox()->setSelected( mConfig.buildType ); + } ); + if ( panelBuildTypeDDL ) + panelBuildTypeDDL->on( + Event::OnItemSelected, [this, buildTypeDropDown, panelBuildTypeDDL]( const Event* ) { + mConfig.buildType = panelBuildTypeDDL->getListBox()->getItemSelectedText().toUtf8(); + if ( buildTypeDropDown ) + buildTypeDropDown->getListBox()->setSelected( mConfig.buildType ); + } ); auto advTitle = querySelector( ".settings_panel > .advanced_options > .title" ); - advTitle->addMouseClickListener( - [this]( const MouseEvent* event ) { - auto img = event->getNode()->findByType( UI_TYPE_IMAGE )->asType(); - findByClass( "inner_box" )->toggleClass( "visible" ); - img->toggleClass( "expanded" ); - }, - MouseButton::EE_BUTTON_LEFT ); + advTitle->onClick( [this]( const MouseEvent* event ) { + auto img = event->getNode()->findByType( UI_TYPE_IMAGE )->asType(); + findByClass( "inner_box" )->toggleClass( "visible" ); + img->toggleClass( "expanded" ); + } ); mDataBindHolder += UIDataBindBool::New( &mBuild.mConfig.clearSysEnv, find( "clear_sys_env" ) ); @@ -230,6 +303,62 @@ UIBuildSettings::UIBuildSettings( ProjectBuild& build, ProjectBuildConfiguration model->setColumnName( 1, getTranslatorString( "var_value", "Value" ) ); tableVars->setAutoColumnsWidth( true ); tableVars->setModel( model ); + + find( "build_type_add" )->onClick( [this, buildTypeDropDown, panelBuildTypeDDL]( auto ) { + UIMessageBox* msgBox = + UIMessageBox::New( UIMessageBox::INPUT, i18n( "build_type_name", "Build Type Name:" ) ); + msgBox->setTitle( i18n( "build_settings", "Build Settings" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->showWhenReady(); + msgBox->addEventListener( + Event::OnConfirm, [this, msgBox, buildTypeDropDown, panelBuildTypeDDL]( const Event* ) { + const auto& buildType = msgBox->getTextInput()->getText(); + mBuild.mBuildTypes.insert( buildType.toUtf8() ); + buildTypeDropDown->getListBox()->addListBoxItem( buildType ); + buildTypeDropDown->getListBox()->setSelected( buildType ); + if ( panelBuildTypeDDL ) { + panelBuildTypeDDL->getListBox()->addListBoxItem( buildType ); + panelBuildTypeDDL->getListBox()->setSelected( buildType ); + } + msgBox->closeWindow(); + } ); + } ); + + find( "build_type_del" )->onClick( [this, buildTypeDropDown, panelBuildTypeDDL]( auto ) { + const auto& txt = buildTypeDropDown->getListBox()->getItemSelectedText(); + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::OK_CANCEL, + String::format( + i18n( "build_type_name_del", "Delete Build Type: %s?" ).toUtf8().c_str(), + txt.toUtf8().c_str() ) ); + msgBox->setTitle( i18n( "build_settings", "Build Settings" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->showWhenReady(); + msgBox->addEventListener( Event::OnConfirm, [this, msgBox, buildTypeDropDown, + panelBuildTypeDDL, txt]( const Event* ) { + mBuild.mBuildTypes.erase( txt.toUtf8() ); + buildTypeDropDown->getListBox()->removeListBoxItem( txt ); + if ( panelBuildTypeDDL ) { + panelBuildTypeDDL->getListBox()->removeListBoxItem( txt ); + } + msgBox->closeWindow(); + } ); + } ); + + auto outputParserPresetsDDL = find( "output_parsers_presets_list" ); + outputParserPresetsDDL->getListBox()->setSelected( mBuild.mOutputParser.mPreset ); + outputParserPresetsDDL->on( Event::OnItemSelected, [this]( const Event* event ) { + std::string txt( event->getNode() + ->asType() + ->getListBox() + ->getItemSelectedText() + .toUtf8() ); + mBuild.mOutputParser.mPreset = txt; + if ( ProjectBuildOutputParser::existsPreset( txt ) ) { + mBuild.mOutputParser.mPresetConfig = + ProjectBuildOutputParser::getPresets()[mBuild.mOutputParser.mPreset].mConfig; + } + } ); } void UIBuildSettings::updateOS() { @@ -241,4 +370,54 @@ void UIBuildSettings::updateOS() { } } +void UIBuildSettings::setTab( UITab* tab ) { + if ( tab != mTab ) { + mTab = tab; + refreshTab(); + } +} + +void UIBuildSettings::refreshTab() { + if ( !mTab ) + return; + mTab->setText( + String::format( ( i18n( "build_seetings", "Build Settings" ) + ": %s" ).toUtf8().c_str(), + mBuild.mName.c_str() ) ); + mTab->setId( "build_settings_" + mBuild.mName ); +} + +void UIBuildSettings::moveStepUp( size_t stepNum, bool isClean ) { + moveStepDir( stepNum, isClean, -1 ); +} + +void UIBuildSettings::moveStepDown( size_t stepNum, bool isClean ) { + moveStepDir( stepNum, isClean, 1 ); +} + +void UIBuildSettings::moveStepDir( size_t stepNum, bool isClean, int dir ) { + ProjectBuildSteps& steps = isClean ? mBuild.mClean : mBuild.mBuild; + UIWidget* cont = + isClean ? find( "build_clean_steps_cont" ) : find( "build_steps_cont" ); + int newStep = (int)stepNum + dir; + std::swap( steps[stepNum], steps[newStep] ); + auto bs1 = cont->findByClass( String::toString( stepNum ) ); + auto bs2 = cont->findByClass( String::toString( newStep ) ); + bs1->updateStep( stepNum, &steps[stepNum] ); + bs2->updateStep( newStep, &steps[newStep] ); +} + +void UIBuildSettings::deleteStep( size_t stepNum, bool isClean ) { + ProjectBuildSteps& steps = isClean ? mBuild.mClean : mBuild.mBuild; + UIWidget* cont = + isClean ? find( "build_clean_steps_cont" ) : find( "build_steps_cont" ); + for ( auto step = stepNum; step < steps.size(); step++ ) + cont->findByClass( String::toString( step ) )->clearBindings(); + // cppcheck-suppress mismatchingContainerIterator + steps.erase( steps.begin() + stepNum ); + cont->findByClass( String::toString( stepNum ) )->close(); + for ( auto step = stepNum + 1; step < steps.size(); step++ ) + cont->findByClass( String::toString( step ) ) + ->updateStep( step, &steps[step] ); +} + } // namespace ecode diff --git a/src/tools/ecode/uibuildsettings.hpp b/src/tools/ecode/uibuildsettings.hpp index 21e4eaec0..df96a8fce 100644 --- a/src/tools/ecode/uibuildsettings.hpp +++ b/src/tools/ecode/uibuildsettings.hpp @@ -13,14 +13,30 @@ class UIBuildSettings : public UIRelativeLayout { public: static UIBuildSettings* New( ProjectBuild& build, ProjectBuildConfiguration& config ); + void setTab( UITab* tab ); + protected: + friend class UIBuildStep; + ProjectBuild& mBuild; ProjectBuildConfiguration& mConfig; UIDataBindHolder mDataBindHolder; + UITab* mTab{ nullptr }; + String mOldName; explicit UIBuildSettings( ProjectBuild& build, ProjectBuildConfiguration& config ); + void moveStepUp( size_t stepNum, bool isClea ); + + void moveStepDown( size_t stepNum, bool isClean ); + + void moveStepDir( size_t stepNum, bool isClean, int dir ); + + void deleteStep( size_t stepNum, bool isClean ); + void updateOS(); + + void refreshTab(); }; } // namespace ecode diff --git a/src/tools/ecode/uiwelcomescreen.cpp b/src/tools/ecode/uiwelcomescreen.cpp index 14f87b0f4..16ac506f9 100644 --- a/src/tools/ecode/uiwelcomescreen.cpp +++ b/src/tools/ecode/uiwelcomescreen.cpp @@ -5,7 +5,7 @@ namespace ecode { -const char* LAYOUT = R"xml( +static const auto LAYOUT = R"xml(