From d1b35f052eb971b1ebe7686609220d9ad2a65df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 4 Jun 2023 22:00:14 -0300 Subject: [PATCH] ecode: ModelEditingDelegate implementation WIP, already working. --- bin/assets/ui/breeze.css | 5 + include/eepp/scene/node.hpp | 4 +- .../eepp/ui/abstract/uiabstracttableview.hpp | 2 +- include/eepp/ui/abstract/uiabstractview.hpp | 36 +++++- include/eepp/ui/models/itemlistmodel.hpp | 97 +++++++++++++++- include/eepp/ui/models/model.hpp | 4 +- .../eepp/ui/models/modeleditingdelegate.hpp | 59 +++++++++- include/eepp/ui/uitablecell.hpp | 2 +- src/eepp/scene/node.cpp | 16 ++- src/eepp/ui/abstract/uiabstracttableview.cpp | 30 +++-- src/eepp/ui/abstract/uiabstractview.cpp | 71 +++++++++++- src/eepp/ui/doc/syntaxdefinitionmanager.cpp | 2 +- src/eepp/ui/doc/textdocument.cpp | 106 +++++++++--------- src/eepp/ui/uitreeview.cpp | 56 +++++---- src/tools/ecode/uibuildsettings.cpp | 29 ++++- 15 files changed, 408 insertions(+), 111 deletions(-) diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index fa1725452..51be4828f 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -1013,6 +1013,11 @@ console { border-bottom-width: var(--border-width); } +TextInput.table_cell_edit { + padding-top: 0!important; + padding-bottom: 0!important; +} + @media (prefers-color-scheme: light) { :root { diff --git a/include/eepp/scene/node.hpp b/include/eepp/scene/node.hpp index 09404ea86..c675b8c53 100644 --- a/include/eepp/scene/node.hpp +++ b/include/eepp/scene/node.hpp @@ -202,6 +202,8 @@ class EE_API Node : public Transformable { void removeEventListener( const Uint32& callbackId ); + void removeEventListener( const std::vector& callbacksIds ); + void clearEventListener(); Node* getFirstChild() const; @@ -427,7 +429,7 @@ class EE_API Node : public Transformable { Rectf getScreenRect() const; protected: - typedef std::map> EventsMap; + typedef std::unordered_map> EventsMap; friend class EventDispatcher; std::string mId; diff --git a/include/eepp/ui/abstract/uiabstracttableview.hpp b/include/eepp/ui/abstract/uiabstracttableview.hpp index fae78b616..a1c0425a5 100644 --- a/include/eepp/ui/abstract/uiabstracttableview.hpp +++ b/include/eepp/ui/abstract/uiabstracttableview.hpp @@ -140,7 +140,7 @@ class EE_API UIAbstractTableView : public UIAbstractView { Action* mSearchTextAction{ nullptr }; std::string mSearchText; size_t mMainColumn{ 0 }; - std::unordered_map mWidgetsClickCbId; + std::unordered_map> mWidgetsClickCbId; virtual ~UIAbstractTableView(); diff --git a/include/eepp/ui/abstract/uiabstractview.hpp b/include/eepp/ui/abstract/uiabstractview.hpp index 51f013189..766dff355 100644 --- a/include/eepp/ui/abstract/uiabstractview.hpp +++ b/include/eepp/ui/abstract/uiabstractview.hpp @@ -1,6 +1,7 @@ #ifndef EE_UI_UIABSTRACTVIEW_HPP #define EE_UI_UIABSTRACTVIEW_HPP +#include #include #include #include @@ -41,6 +42,13 @@ class EE_API ModelEvent : public Event { class EE_API UIAbstractView : public UIScrollableWidget { public: + enum EditTrigger { + None = 0, + DoubleClicked = 1 << 0, + EditKeyPressed = 1 << 1, + AnyKeyPressed = 1 << 2, + }; + Uint32 getType() const; bool isType( const Uint32& type ) const; @@ -72,6 +80,24 @@ class EE_API UIAbstractView : public UIScrollableWidget { virtual ModelIndex findRowWithText( const std::string& text, const bool& caseSensitive = false, const bool& exactMatch = false ) const; + bool isEditable() const; + + void setEditable( bool editable ); + + Uint32 getEditTriggers() const; + + void setEditTriggers( Uint32 editTriggers ); + + KeyBindings::Shortcut getEditShortcut() const; + + void setEditShortcut( const KeyBindings::Shortcut& editShortcut ); + + void beginEditing( const ModelIndex& index, UIWidget* editedWidget ); + + void stopEditing(); + + std::function onCreateEditingDelegate; + protected: friend class EE::UI::Models::Model; @@ -87,15 +113,19 @@ class EE_API UIAbstractView : public UIScrollableWidget { bool mEditable{ false }; ModelIndex mEditIndex; - UIWidget* mEditWidget; - Rect mEditWidgetContentRect; + UIWidget* mEditWidget{ nullptr }; std::shared_ptr mModel; - std::unique_ptr mEditingDelegate; + ModelEditingDelegate* mEditingDelegate{ nullptr }; ModelSelection mSelection; std::function mOnSelectionChange; std::function mOnSelection; + + Uint32 mEditTriggers{ EditTrigger::None }; + KeyBindings::Shortcut mEditShortcut{ KEY_F2 }; + + virtual void editingWidgetDidChange( const ModelIndex& ) {} }; }}} // namespace EE::UI::Abstract diff --git a/include/eepp/ui/models/itemlistmodel.hpp b/include/eepp/ui/models/itemlistmodel.hpp index edb54ffe3..7157ce2fc 100644 --- a/include/eepp/ui/models/itemlistmodel.hpp +++ b/include/eepp/ui/models/itemlistmodel.hpp @@ -23,6 +23,13 @@ template class ItemListModel final : public Model { virtual std::string columnName( const size_t& ) const { return "Data"; } + virtual ModelIndex index( int row, int column, + const ModelIndex& parent = ModelIndex() ) const override { + if ( row >= (int)rowCount( parent ) || column >= (int)columnCount( parent ) ) + return {}; + return Model::index( row, column, parent ); + } + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { if ( role == ModelRole::Display ) return Variant( mData[index.row()] ); @@ -37,11 +44,11 @@ template class ItemListModel final : public Model { template class ItemPairListModel final : public Model { public: - static std::shared_ptr create( const std::vector>& data ) { + static std::shared_ptr create( std::vector>& data ) { return std::make_shared>( data ); } - explicit ItemPairListModel( const std::vector>& data ) : mData( data ) {} + explicit ItemPairListModel( std::vector>& data ) : mData( data ) {} virtual ~ItemPairListModel() {} @@ -59,6 +66,13 @@ template class ItemPairListModel final : public Model { mColumnNames[index] = name; } + virtual ModelIndex index( int row, int column, + const ModelIndex& parent = ModelIndex() ) const override { + if ( row >= (int)rowCount( parent ) || column >= (int)columnCount( parent ) ) + return {}; + return Model::index( row, column, parent ); + } + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { if ( role == ModelRole::Display ) { switch ( index.column() ) { @@ -74,9 +88,25 @@ template class ItemPairListModel final : public Model { virtual void update() { onModelUpdate(); } + virtual bool isEditable( const ModelIndex& ) const { return mIsEditable; } + + void setIsEditable( bool isEditable ) { mIsEditable = isEditable; } + + // TODO: Fix this + virtual void setData( const ModelIndex& index, const Variant& val ) { + if ( mIsEditable && index.row() < (int)mData.size() ) { + if ( index.column() == 0 ) { + mData[index.row()].first = val.toString(); + } else { + mData[index.row()].second = val.toString(); + } + } + } + private: - const std::vector>& mData; + std::vector>& mData; std::vector mColumnNames{ "Title", "Description" }; + bool mIsEditable{ false }; }; template class ItemListOwnerModel final : public Model { @@ -95,6 +125,13 @@ template class ItemListOwnerModel final : public Model { virtual std::string columnName( const size_t& ) const { return "Data"; } + virtual ModelIndex index( int row, int column, + const ModelIndex& parent = ModelIndex() ) const override { + if ( row >= (int)rowCount( parent ) || column >= (int)columnCount( parent ) ) + return {}; + return Model::index( row, column, parent ); + } + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { if ( role == ModelRole::Display ) return Variant( mData[index.row()] ); @@ -103,8 +140,19 @@ template class ItemListOwnerModel final : public Model { virtual void update() { onModelUpdate(); } + virtual bool isEditable( const ModelIndex& ) const { return mIsEditable; } + + void setIsEditable( bool isEditable ) { mIsEditable = isEditable; } + + // TODO: Fix this + virtual void setData( const ModelIndex& index, const Variant& val ) { + if ( mIsEditable && index.row() < (int)mData.size() ) + mData[index.row()] = val.toString(); + } + private: std::vector mData; + bool mIsEditable{ false }; }; template class ItemPairListOwnerModel final : public Model { @@ -132,6 +180,13 @@ template class ItemPairListOwnerModel final : public Mo mColumnNames[index] = name; } + virtual ModelIndex index( int row, int column, + const ModelIndex& parent = ModelIndex() ) const override { + if ( row >= (int)rowCount( parent ) || column >= (int)columnCount( parent ) ) + return {}; + return Model::index( row, column, parent ); + } + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { if ( role == ModelRole::Display ) { switch ( index.column() ) { @@ -147,9 +202,25 @@ template class ItemPairListOwnerModel final : public Mo virtual void update() { onModelUpdate(); } + virtual bool isEditable( const ModelIndex& ) const { return mIsEditable; } + + void setIsEditable( bool isEditable ) { mIsEditable = isEditable; } + + // TODO: Fix this + virtual void setData( const ModelIndex& index, const Variant& val ) { + if ( mIsEditable && index.row() < (int)mData.size() ) { + if ( index.column() == 0 ) { + mData[index.row()].first = val.toString(); + } else { + mData[index.row()].second = val.toString(); + } + } + } + private: std::vector> mData; std::vector mColumnNames{ "Title", "Description" }; + bool mIsEditable{ false }; }; template class ItemVectorListOwnerModel final : public Model { @@ -181,6 +252,13 @@ template class ItemVectorListOwnerModel final : public Model { mColumnNames[index] = name; } + virtual ModelIndex index( int row, int column, + const ModelIndex& parent = ModelIndex() ) const override { + if ( row >= (int)rowCount( parent ) || column >= (int)columnCount( parent ) ) + return {}; + return Model::index( row, column, parent ); + } + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const { eeASSERT( index.row() < (Int64)mData.size() ); eeASSERT( index.column() < (Int64)mData[index.row()].size() ); @@ -196,9 +274,22 @@ template class ItemVectorListOwnerModel final : public Model { virtual void update() { onModelUpdate(); } + virtual bool isEditable( const ModelIndex& ) const { return mIsEditable; } + + void setIsEditable( bool isEditable ) { mIsEditable = isEditable; } + + // TODO: Fix this + virtual void setData( const ModelIndex& index, const Variant& val ) { + if ( mIsEditable && index.row() < (int)mData.size() && + index.column() < (int)mData[index.row()].size() ) { + mData[index.row()][index.column()] = val.toString(); + } + } + private: std::vector> mData; std::vector mColumnNames; + bool mIsEditable{ false }; }; }}} // namespace EE::UI::Models diff --git a/include/eepp/ui/models/model.hpp b/include/eepp/ui/models/model.hpp index 161f1068c..b4c4498c3 100644 --- a/include/eepp/ui/models/model.hpp +++ b/include/eepp/ui/models/model.hpp @@ -90,6 +90,8 @@ class EE_API Model { virtual std::string dragDataType() const { return {}; } + virtual bool isEditable( const ModelIndex& ) const { return false; } + bool isValid( const ModelIndex& index ) const { auto parentIndex = this->parentIndex( index ); return index.row() >= 0 && index.row() < (Int64)rowCount( parentIndex ) && @@ -206,8 +208,6 @@ class EE_API Model { Mutex mResourceLock; }; - - }}} // namespace EE::UI::Models #endif // EE_UI_MODELS_MODEL_HPP diff --git a/include/eepp/ui/models/modeleditingdelegate.hpp b/include/eepp/ui/models/modeleditingdelegate.hpp index 530f588e5..39c3b27d1 100644 --- a/include/eepp/ui/models/modeleditingdelegate.hpp +++ b/include/eepp/ui/models/modeleditingdelegate.hpp @@ -2,6 +2,7 @@ #define EE_UI_MODELEDITINGDELEGATE_HPP #include +#include #include #include @@ -14,7 +15,7 @@ class EE_API ModelEditingDelegate { SelectAll, }; - virtual ~ModelEditingDelegate() {} + virtual ~ModelEditingDelegate() = default; void bind( std::shared_ptr model, const ModelIndex& index ) { if ( mModel.get() == model.get() && mIndex == index ) @@ -32,12 +33,23 @@ class EE_API ModelEditingDelegate { std::function onChange; virtual Variant getValue() const = 0; - virtual void setValue( const Variant&, - SelectionBehavior selectionBehavior = SelectionBehavior::SelectAll ) = 0; + + virtual void setValue( const Variant& ) = 0; + virtual void willBeginEditing() {} + ModelIndex const& index() const { return mIndex; } + + ModelEditingDelegate::SelectionBehavior getSelectionBehavior() const { + return mSelectionBehavior; + } + + void setSelectionBehavior( SelectionBehavior selectionBehavior ) { + mSelectionBehavior = selectionBehavior; + } + protected: - ModelEditingDelegate() {} + ModelEditingDelegate() = default; virtual UIWidget* createWidget() = 0; @@ -59,6 +71,45 @@ class EE_API ModelEditingDelegate { std::shared_ptr mModel; ModelIndex mIndex; UIWidget* mWidget{ nullptr }; + + protected: + SelectionBehavior mSelectionBehavior{ SelectionBehavior::SelectAll }; +}; + +class EE_API StringModelEditingDelegate : public ModelEditingDelegate { + public: + static StringModelEditingDelegate* New() { return eeNew( StringModelEditingDelegate, () ); } + + StringModelEditingDelegate() = default; + + virtual ~StringModelEditingDelegate() = default; + + Variant getValue() const override { + return Variant( getWidget()->asType()->getText() ); + }; + + void setValue( const Variant& val ) override { + getWidget()->asType()->setText( val.toString() ); + } + + void willBeginEditing() override { + if ( mSelectionBehavior == SelectionBehavior::SelectAll ) + getWidget()->asType()->getDocument().selectAll(); + } + + protected: + UIWidget* createWidget() override { + auto input = UITextInput::New(); + input->addClass( "table_cell_edit" ); + input->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + input->addEventListener( Event::OnPressEnter, [this]( auto ) { commit(); } ); + input->addEventListener( Event::KeyUp, [this]( const Event* event ) { + if ( event->asKeyEvent()->getKeyCode() == KEY_ESCAPE ) + rollback(); + } ); + input->addEventListener( Event::OnValueChange, [this]( auto ) { change(); } ); + return input; + } }; }}} // namespace EE::UI::Models diff --git a/include/eepp/ui/uitablecell.hpp b/include/eepp/ui/uitablecell.hpp index 21258db98..f94e65ac3 100644 --- a/include/eepp/ui/uitablecell.hpp +++ b/include/eepp/ui/uitablecell.hpp @@ -37,7 +37,7 @@ class EE_API UITableCell : public UIPushButton { void setTheme( UITheme* Theme ) { UIPushButton::setTheme( Theme ); - setThemeSkin( Theme, "tablerow" ); + setThemeSkin( Theme, "tablecell" ); onThemeLoaded(); } diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index 3ee806242..d820d1d0c 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1126,7 +1126,7 @@ Uint32 Node::addEventListener( const Uint32& eventType, const EventCallback& cal } Uint32 Node::onClick( const std::function& callback, - const MouseButton& button ) { + const MouseButton& button ) { return addEventListener( Event::MouseClick, [callback, button]( const Event* event ) { if ( event->asMouseEvent()->getFlags() & ( EE_BUTTON_MASK( button ) ) ) { callback( event->asMouseEvent() ); @@ -1143,12 +1143,24 @@ void Node::removeEventsOfType( const Uint32& eventType ) { void Node::removeEventListener( const Uint32& callbackId ) { EventsMap::iterator it; for ( it = mEvents.begin(); it != mEvents.end(); ++it ) { - std::map& event = it->second; + auto& event = it->second; if ( event.erase( callbackId ) > 0 ) break; } } +void Node::removeEventListener( const std::vector& callbacksIds ) { + for ( auto& event : mEvents ) { + auto& events = event.second; + for ( auto& cbId : callbacksIds ) { + auto it = events.find( cbId ); + if ( it != events.end() ) { + events.erase( it ); + } + } + } +} + void Node::clearEventListener() { mEvents.clear(); } diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index 5c5f111d4..4fa97c6be 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -453,23 +453,29 @@ void UIAbstractTableView::onScrollChange() { } void UIAbstractTableView::bindNavigationClick( UIWidget* widget ) { - mWidgetsClickCbId[widget] = widget->addEventListener( - mSingleClickNavigation ? Event::MouseClick : Event::MouseDoubleClick, - [&]( const Event* event ) { + mWidgetsClickCbId[widget].push_back( + widget->addEventListener( Event::MouseDoubleClick, [this]( const Event* event ) { auto mouseEvent = static_cast( event ); + auto cellIdx = mouseEvent->getNode()->asType()->getCurIndex(); auto idx = mouseEvent->getNode()->getParent()->asType()->getCurIndex(); - if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) { + if ( isEditable() && ( mEditTriggers & EditTrigger::DoubleClicked ) && getModel() && + getModel()->isEditable( cellIdx ) ) { + beginEditing( cellIdx, mouseEvent->getNode()->asType() ); + } else if ( ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) && !mSingleClickNavigation ) { onOpenModelIndex( idx, event ); } - } ); + } ) ); - widget->addEventListener( Event::MouseClick, [&]( const Event* event ) { - auto mouseEvent = static_cast( event ); - auto idx = mouseEvent->getNode()->getParent()->asType()->getCurIndex(); - if ( mouseEvent->getFlags() & EE_BUTTON_RMASK ) { - onOpenMenuModelIndex( idx, event ); - } - } ); + mWidgetsClickCbId[widget].push_back( + widget->addEventListener( Event::MouseClick, [this]( const Event* event ) { + auto mouseEvent = static_cast( event ); + auto idx = mouseEvent->getNode()->getParent()->asType()->getCurIndex(); + if ( mouseEvent->getFlags() & EE_BUTTON_RMASK ) { + onOpenMenuModelIndex( idx, event ); + } else if ( ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) && mSingleClickNavigation ) { + onOpenModelIndex( idx, event ); + } + } ) ); } UIWidget* UIAbstractTableView::createCell( UIWidget* rowWidget, const ModelIndex& index ) { diff --git a/src/eepp/ui/abstract/uiabstractview.cpp b/src/eepp/ui/abstract/uiabstractview.cpp index 335b1f746..b486e787a 100644 --- a/src/eepp/ui/abstract/uiabstractview.cpp +++ b/src/eepp/ui/abstract/uiabstractview.cpp @@ -7,7 +7,33 @@ namespace EE { namespace UI { namespace Abstract { UIAbstractView::UIAbstractView( const std::string& tag ) : UIScrollableWidget( tag ), mSelection( this ) {} -UIAbstractView::~UIAbstractView() {} +UIAbstractView::~UIAbstractView() { + eeSAFE_DELETE( mEditingDelegate ); +} + +KeyBindings::Shortcut UIAbstractView::getEditShortcut() const { + return mEditShortcut; +} + +void UIAbstractView::setEditShortcut( const KeyBindings::Shortcut& editShortcut ) { + mEditShortcut = editShortcut; +} + +Uint32 UIAbstractView::getEditTriggers() const { + return mEditTriggers; +} + +void UIAbstractView::setEditTriggers( Uint32 editTriggers ) { + mEditTriggers = editTriggers; +} + +bool UIAbstractView::isEditable() const { + return mEditable; +} + +void UIAbstractView::setEditable( bool editable ) { + mEditable = editable; +} std::function UIAbstractView::getOnSelection() const { return mOnSelection; @@ -77,4 +103,47 @@ ModelIndex UIAbstractView::findRowWithText( const std::string&, const bool&, con return {}; } +void UIAbstractView::beginEditing( const ModelIndex& index, UIWidget* editedWidget ) { + if ( !isEditable() || !mModel || mEditIndex == index || !mModel->isEditable( index ) || + !onCreateEditingDelegate ) + return; + + if ( mEditWidget ) { + mEditWidget->setVisible( false )->setEnabled( false )->close(); + mEditWidget = nullptr; + } + eeSAFE_DELETE( mEditingDelegate ); + + mEditIndex = index; + mEditingDelegate = onCreateEditingDelegate( index ); + mEditingDelegate->bind( mModel, index ); + mEditingDelegate->setValue( index.data() ); + mEditWidget = mEditingDelegate->getWidget(); + mEditWidget->setParent( editedWidget ); + mEditWidget->setSize( editedWidget->getSize() ); + mEditWidget->setFocus(); + mEditWidget->toFront(); + mEditingDelegate->willBeginEditing(); + mEditingDelegate->onCommit = [this]() { + if ( getModel() ) + getModel()->setData( mEditIndex, mEditingDelegate->getValue() ); + stopEditing(); + }; + mEditingDelegate->onRollback = [this]() { stopEditing(); }; + mEditingDelegate->onChange = [this, index]() { editingWidgetDidChange( index ); }; + // mEditWidget->on( Event::OnFocusLoss, [this]( auto ) { mEditingDelegate->onRollback(); } ); +} + +void UIAbstractView::stopEditing() { + bool recoverFocus = false; + mEditIndex = {}; + if ( mEditWidget ) { + recoverFocus = mEditWidget->hasFocusWithin(); + mEditWidget->setVisible( false )->setEnabled( false )->close(); + mEditWidget = nullptr; + } + if ( recoverFocus ) + setFocus(); +} + }}} // namespace EE::UI::Abstract diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index 47176f0fe..34acac700 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -1853,7 +1853,7 @@ static void addMeson() { static void addAngelScript() { SyntaxDefinitionManager::instance()->add( - { "AlgelScript", + { "AngelScript", { "%.as$", "%.asc$" }, { { { "//.-\n" }, "comment" }, diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index ff9c8ffad..4f8a7ca64 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -2634,59 +2634,59 @@ void TextDocument::notifiyDocumenLineMove( const Int64& fromLine, const Int64& n } void TextDocument::initializeCommands() { - mCommands["reset"] = [&] { reset(); }; - mCommands["save"] = [&] { save(); }; - mCommands["delete-to-previous-word"] = [&] { deleteToPreviousWord(); }; - mCommands["delete-to-previous-char"] = [&] { deleteToPreviousChar(); }; - mCommands["delete-to-next-word"] = [&] { deleteToNextWord(); }; - mCommands["delete-to-next-char"] = [&] { deleteToNextChar(); }; - mCommands["delete-current-line"] = [&] { deleteCurrentLine(); }; - mCommands["delete-selection"] = [&] { deleteSelection(); }; - mCommands["move-to-previous-char"] = [&] { moveToPreviousChar(); }; - mCommands["move-to-previous-word"] = [&] { moveToPreviousWord(); }; - mCommands["move-to-next-char"] = [&] { moveToNextChar(); }; - mCommands["move-to-next-word"] = [&] { moveToNextWord(); }; - mCommands["move-to-previous-line"] = [&] { moveToPreviousLine(); }; - mCommands["move-to-next-line"] = [&] { moveToNextLine(); }; - mCommands["move-to-previous-page"] = [&] { moveToPreviousPage( mPageSize ); }; - mCommands["move-to-next-page"] = [&] { moveToNextPage( mPageSize ); }; - mCommands["move-to-start-of-doc"] = [&] { moveToStartOfDoc(); }; - mCommands["move-to-end-of-doc"] = [&] { moveToEndOfDoc(); }; - mCommands["move-to-start-of-line"] = [&] { moveToStartOfLine(); }; - mCommands["move-to-end-of-line"] = [&] { moveToEndOfLine(); }; - mCommands["move-to-start-of-content"] = [&] { moveToStartOfContent(); }; - mCommands["move-lines-up"] = [&] { moveLinesUp(); }; - mCommands["move-lines-down"] = [&] { moveLinesDown(); }; - mCommands["select-to-previous-char"] = [&] { selectToPreviousChar(); }; - mCommands["select-to-previous-word"] = [&] { selectToPreviousWord(); }; - mCommands["select-to-previous-line"] = [&] { selectToPreviousLine(); }; - mCommands["select-to-next-char"] = [&] { selectToNextChar(); }; - mCommands["select-to-next-word"] = [&] { selectToNextWord(); }; - mCommands["select-to-next-line"] = [&] { selectToNextLine(); }; - mCommands["select-word"] = [&] { selectWord(); }; - mCommands["select-line"] = [&] { selectLine(); }; - mCommands["select-to-start-of-line"] = [&] { selectToStartOfLine(); }; - mCommands["select-to-end-of-line"] = [&] { selectToEndOfLine(); }; - mCommands["select-to-start-of-doc"] = [&] { selectToStartOfDoc(); }; - mCommands["select-to-start-of-content"] = [&] { selectToStartOfContent(); }; - mCommands["select-to-end-of-doc"] = [&] { selectToEndOfDoc(); }; - mCommands["select-to-previous-page"] = [&] { selectToPreviousPage( mPageSize ); }; - mCommands["select-to-next-page"] = [&] { selectToNextPage( mPageSize ); }; - mCommands["select-all"] = [&] { selectAll(); }; - mCommands["new-line"] = [&] { newLine(); }; - mCommands["new-line-above"] = [&] { newLineAbove(); }; - mCommands["indent"] = [&] { indent(); }; - mCommands["unindent"] = [&] { unindent(); }; - mCommands["undo"] = [&] { undo(); }; - mCommands["redo"] = [&] { redo(); }; - mCommands["toggle-line-comments"] = [&] { toggleLineComments(); }; - mCommands["selection-to-upper"] = [&] { toUpperSelection(); }; - mCommands["selection-to-lower"] = [&] { toLowerSelection(); }; - mCommands["reset-cursor"] = [&] { resetCursor(); }; - mCommands["add-cursor-above"] = [&] { addCursorAbove(); }; - mCommands["add-cursor-below"] = [&] { addCursorBelow(); }; - mCommands["cursor-undo"] = [&] { cursorUndo(); }; - mCommands["select-all-matches"] = [&] { selectAllMatches(); }; + mCommands["reset"] = [this] { reset(); }; + mCommands["save"] = [this] { save(); }; + mCommands["delete-to-previous-word"] = [this] { deleteToPreviousWord(); }; + mCommands["delete-to-previous-char"] = [this] { deleteToPreviousChar(); }; + mCommands["delete-to-next-word"] = [this] { deleteToNextWord(); }; + mCommands["delete-to-next-char"] = [this] { deleteToNextChar(); }; + mCommands["delete-current-line"] = [this] { deleteCurrentLine(); }; + mCommands["delete-selection"] = [this] { deleteSelection(); }; + mCommands["move-to-previous-char"] = [this] { moveToPreviousChar(); }; + mCommands["move-to-previous-word"] = [this] { moveToPreviousWord(); }; + mCommands["move-to-next-char"] = [this] { moveToNextChar(); }; + mCommands["move-to-next-word"] = [this] { moveToNextWord(); }; + mCommands["move-to-previous-line"] = [this] { moveToPreviousLine(); }; + mCommands["move-to-next-line"] = [this] { moveToNextLine(); }; + mCommands["move-to-previous-page"] = [this] { moveToPreviousPage( mPageSize ); }; + mCommands["move-to-next-page"] = [this] { moveToNextPage( mPageSize ); }; + mCommands["move-to-start-of-doc"] = [this] { moveToStartOfDoc(); }; + mCommands["move-to-end-of-doc"] = [this] { moveToEndOfDoc(); }; + mCommands["move-to-start-of-line"] = [this] { moveToStartOfLine(); }; + mCommands["move-to-end-of-line"] = [this] { moveToEndOfLine(); }; + mCommands["move-to-start-of-content"] = [this] { moveToStartOfContent(); }; + mCommands["move-lines-up"] = [this] { moveLinesUp(); }; + mCommands["move-lines-down"] = [this] { moveLinesDown(); }; + mCommands["select-to-previous-char"] = [this] { selectToPreviousChar(); }; + mCommands["select-to-previous-word"] = [this] { selectToPreviousWord(); }; + mCommands["select-to-previous-line"] = [this] { selectToPreviousLine(); }; + mCommands["select-to-next-char"] = [this] { selectToNextChar(); }; + mCommands["select-to-next-word"] = [this] { selectToNextWord(); }; + mCommands["select-to-next-line"] = [this] { selectToNextLine(); }; + mCommands["select-word"] = [this] { selectWord(); }; + mCommands["select-line"] = [this] { selectLine(); }; + mCommands["select-to-start-of-line"] = [this] { selectToStartOfLine(); }; + mCommands["select-to-end-of-line"] = [this] { selectToEndOfLine(); }; + mCommands["select-to-start-of-doc"] = [this] { selectToStartOfDoc(); }; + mCommands["select-to-start-of-content"] = [this] { selectToStartOfContent(); }; + mCommands["select-to-end-of-doc"] = [this] { selectToEndOfDoc(); }; + mCommands["select-to-previous-page"] = [this] { selectToPreviousPage( mPageSize ); }; + mCommands["select-to-next-page"] = [this] { selectToNextPage( mPageSize ); }; + mCommands["select-all"] = [this] { selectAll(); }; + mCommands["new-line"] = [this] { newLine(); }; + mCommands["new-line-above"] = [this] { newLineAbove(); }; + mCommands["indent"] = [this] { indent(); }; + mCommands["unindent"] = [this] { unindent(); }; + mCommands["undo"] = [this] { undo(); }; + mCommands["redo"] = [this] { redo(); }; + mCommands["toggle-line-comments"] = [this] { toggleLineComments(); }; + mCommands["selection-to-upper"] = [this] { toUpperSelection(); }; + mCommands["selection-to-lower"] = [this] { toLowerSelection(); }; + mCommands["reset-cursor"] = [this] { resetCursor(); }; + mCommands["add-cursor-above"] = [this] { addCursorAbove(); }; + mCommands["add-cursor-below"] = [this] { addCursorBelow(); }; + mCommands["cursor-undo"] = [this] { cursorUndo(); }; + mCommands["select-all-matches"] = [this] { selectAllMatches(); }; } TextRange TextDocument::getTopMostCursor() { diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 3c55465fc..d6f204e29 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -113,32 +113,42 @@ void UITreeView::updateContentSize() { } void UITreeView::bindNavigationClick( UIWidget* widget ) { - mWidgetsClickCbId[widget] = widget->addEventListener( - mSingleClickNavigation ? Event::MouseClick : Event::MouseDoubleClick, - [&]( const Event* event ) { + auto openTree = [this]( const ModelIndex& idx, const Event* event ) { + ConditionalLock l( getModel() != nullptr, + getModel() ? &getModel()->resourceMutex() : nullptr ); + if ( getModel()->rowCount( idx ) ) { + auto& data = getIndexMetadata( idx ); + data.open = !data.open; + createOrUpdateColumns( false ); + onOpenTreeModelIndex( idx, data.open ); + } else { + onOpenModelIndex( idx, event ); + } + }; + + mWidgetsClickCbId[widget].push_back( + widget->addEventListener( Event::MouseDoubleClick, [this, openTree]( const Event* event ) { + auto mouseEvent = static_cast( event ); + auto cellIdx = mouseEvent->getNode()->asType()->getCurIndex(); + auto idx = mouseEvent->getNode()->getParent()->asType()->getCurIndex(); + if ( isEditable() && ( mEditTriggers & EditTrigger::DoubleClicked ) && getModel() && + getModel()->isEditable( cellIdx ) ) { + beginEditing( cellIdx, mouseEvent->getNode()->asType() ); + } else if ( ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) && !mSingleClickNavigation ) { + openTree( idx, event ); + } + } ) ); + + mWidgetsClickCbId[widget].push_back( + widget->addEventListener( Event::MouseClick, [this, openTree]( const Event* event ) { auto mouseEvent = static_cast( event ); auto idx = mouseEvent->getNode()->getParent()->asType()->getCurIndex(); - if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) { - ConditionalLock l( getModel() != nullptr, - getModel() ? &getModel()->resourceMutex() : nullptr ); - if ( getModel()->rowCount( idx ) ) { - auto& data = getIndexMetadata( idx ); - data.open = !data.open; - createOrUpdateColumns( false ); - onOpenTreeModelIndex( idx, data.open ); - } else { - onOpenModelIndex( idx, event ); - } + if ( mouseEvent->getFlags() & EE_BUTTON_RMASK ) { + onOpenMenuModelIndex( idx, event ); + } else if ( ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) && mSingleClickNavigation ) { + openTree( idx, event ); } - } ); - - widget->addEventListener( Event::MouseClick, [&]( const Event* event ) { - auto mouseEvent = static_cast( event ); - auto idx = mouseEvent->getNode()->getParent()->asType()->getCurIndex(); - if ( mouseEvent->getFlags() & EE_BUTTON_RMASK ) { - onOpenMenuModelIndex( idx, event ); - } - } ); + } ) ); } bool UITreeView::tryOpenModelIndex( const ModelIndex& index, bool forceUpdate ) { diff --git a/src/tools/ecode/uibuildsettings.cpp b/src/tools/ecode/uibuildsettings.cpp index 08d8b6506..b402745af 100644 --- a/src/tools/ecode/uibuildsettings.cpp +++ b/src/tools/ecode/uibuildsettings.cpp @@ -164,6 +164,8 @@ static const auto SETTINGS_PANEL_XML = R"xml( + + @@ -310,12 +312,31 @@ UIBuildSettings::UIBuildSettings( ProjectBuild& build, ProjectBuildConfiguration mDataBindHolder += UIDataBindBool::New( &mBuild.mConfig.clearSysEnv, find( "clear_sys_env" ) ); + UITableView* tableEnvs = find( "table_vars" ); + auto modelEnvs = ItemPairListModel::create( mBuild.mEnvs ); + modelEnvs->setIsEditable( true ); + modelEnvs->setColumnName( 0, getTranslatorString( "env_name", "Name" ) ); + modelEnvs->setColumnName( 1, getTranslatorString( "env_value", "Value" ) ); + tableEnvs->setAutoColumnsWidth( true ); + tableEnvs->setModel( modelEnvs ); + tableEnvs->setEditable( true ); + tableEnvs->setEditTriggers( UIAbstractView::EditTrigger::DoubleClicked ); + tableEnvs->onCreateEditingDelegate = []( const ModelIndex& ) { + return StringModelEditingDelegate::New(); + }; + UITableView* tableVars = find( "table_vars" ); - auto model = ItemPairListModel::create( mBuild.mVars ); - model->setColumnName( 0, getTranslatorString( "var_name", "Name" ) ); - model->setColumnName( 1, getTranslatorString( "var_value", "Value" ) ); + auto modelVars = ItemPairListModel::create( mBuild.mVars ); + modelVars->setColumnName( 0, getTranslatorString( "var_name", "Name" ) ); + modelVars->setColumnName( 1, getTranslatorString( "var_value", "Value" ) ); + modelVars->setIsEditable( true ); tableVars->setAutoColumnsWidth( true ); - tableVars->setModel( model ); + tableVars->setModel( modelVars ); + tableVars->setEditable( true ); + tableVars->setEditTriggers( UIAbstractView::EditTrigger::DoubleClicked ); + tableVars->onCreateEditingDelegate = []( const ModelIndex& ) { + return StringModelEditingDelegate::New(); + }; find( "build_type_add" )->onClick( [this, buildTypeDropDown, panelBuildTypeDDL]( auto ) { UIMessageBox* msgBox =