diff --git a/bin/assets/ui/uitheme.css b/bin/assets/ui/uitheme.css index 544304ed5..fc75399d3 100644 --- a/bin/assets/ui/uitheme.css +++ b/bin/assets/ui/uitheme.css @@ -28,8 +28,8 @@ MenuBar { } MenuBar::button { - padding-left: -3dp; - padding-right: -3dp; + padding-left: 4dp; + padding-right: 4dp; } Menu, diff --git a/include/eepp/scene/event.hpp b/include/eepp/scene/event.hpp index cd5c265e1..e70ef5a48 100644 --- a/include/eepp/scene/event.hpp +++ b/include/eepp/scene/event.hpp @@ -75,6 +75,7 @@ class EE_API Event { OnSave, OnModelEvent, OnResourceChange, + OnActiveWidgetChange, UserEvent, NoEvent = eeINDEX_NOT_FOUND }; diff --git a/include/eepp/scene/node.hpp b/include/eepp/scene/node.hpp index b6eac49be..56d873c6a 100644 --- a/include/eepp/scene/node.hpp +++ b/include/eepp/scene/node.hpp @@ -326,6 +326,8 @@ class EE_API Node : public Transformable { bool hasFocus() const; + bool hasFocusWithin() const; + virtual void setFocus(); Node* getFirstWidget() const; diff --git a/include/eepp/ui/abstract/uiabstracttableview.hpp b/include/eepp/ui/abstract/uiabstracttableview.hpp index 76668a8c3..303f26627 100644 --- a/include/eepp/ui/abstract/uiabstracttableview.hpp +++ b/include/eepp/ui/abstract/uiabstracttableview.hpp @@ -89,31 +89,27 @@ class EE_API UIAbstractTableView : public UIAbstractView { void setRowSearchByName( bool rowSearchByName ); - virtual ModelIndex findRowWithText( const std::string& text, - const bool& caseSensitive = false, - const bool& exactMatch = false ); - protected: friend class EE::UI::UITableHeaderColumn; struct ColumnData { - Float minWidth{0}; - Float width{0}; - bool visible{true}; - UIPushButton* widget{nullptr}; + Float minWidth{ 0 }; + Float width{ 0 }; + bool visible{ true }; + UIPushButton* widget{ nullptr }; }; - Float mRowHeight{0}; + Float mRowHeight{ 0 }; mutable std::vector mRows; mutable std::vector mColumn; mutable std::vector> mWidgets; UILinearLayout* mHeader; - Float mDragBorderDistance{8}; - size_t mIconSize{12}; - size_t mSortIconSize{16}; - bool mAutoExpandOnSingleColumn{false}; - bool mRowSearchByName{true}; - Action* mSearchTextAction{nullptr}; + Float mDragBorderDistance{ 8 }; + size_t mIconSize{ 12 }; + size_t mSortIconSize{ 16 }; + bool mAutoExpandOnSingleColumn{ false }; + bool mRowSearchByName{ true }; + Action* mSearchTextAction{ nullptr }; std::string mSearchText; virtual ~UIAbstractTableView(); diff --git a/include/eepp/ui/abstract/uiabstractview.hpp b/include/eepp/ui/abstract/uiabstractview.hpp index d12642bed..b04f67929 100644 --- a/include/eepp/ui/abstract/uiabstractview.hpp +++ b/include/eepp/ui/abstract/uiabstractview.hpp @@ -36,7 +36,7 @@ class EE_API ModelEvent : public Event { const Model* model; ModelIndex index; ModelEventType modelEventType; - const Event* triggerEvent{nullptr}; + const Event* triggerEvent{ nullptr }; }; class EE_API UIAbstractView : public UIScrollableWidget { @@ -67,6 +67,9 @@ class EE_API UIAbstractView : public UIScrollableWidget { void setOnSelection( const std::function& onSelection ); + virtual ModelIndex findRowWithText( const std::string& text, const bool& caseSensitive = false, + const bool& exactMatch = false ) const; + protected: friend class EE::UI::Models::Model; @@ -78,7 +81,7 @@ class EE_API UIAbstractView : public UIScrollableWidget { virtual ~UIAbstractView(); - bool mEditable{false}; + bool mEditable{ false }; ModelIndex mEditIndex; UIWidget* mEditWidget; Rect mEditWidgetContentRect; diff --git a/include/eepp/ui/uifiledialog.hpp b/include/eepp/ui/uifiledialog.hpp index b49575adf..b4b29e86b 100644 --- a/include/eepp/ui/uifiledialog.hpp +++ b/include/eepp/ui/uifiledialog.hpp @@ -5,7 +5,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -40,7 +42,7 @@ class EE_API UIFileDialog : public UIWindow { virtual void setTheme( UITheme* Theme ); - void refreshFolder(); + void refreshFolder( bool resetScroll = false ); virtual Uint32 onMessage( const NodeMessage* Msg ); @@ -60,7 +62,7 @@ class EE_API UIFileDialog : public UIWindow { UIPushButton* getButtonUp() const; - UIListView* getList() const; + UIMultiModelView* getMultiView() const; UITextInput* getPathInput() const; @@ -98,12 +100,31 @@ class EE_API UIFileDialog : public UIWindow { void setCloseShortcut( const KeyBindings::Shortcut& closeWithKey ); + UIIcon* getIconNewFolder() const; + + void setIconNewFolder( UIIcon* iconNewFolder ); + + UIIcon* getIconListView() const; + + void setIconListView( UIIcon* iconListView ); + + UIIcon* getIconTableView() const; + + void setIconTableView( UIIcon* iconTableView ); + + void setViewMode( const UIMultiModelView::ViewMode& viewMode ); + + const UIMultiModelView::ViewMode& getViewMode() const; + protected: std::string mCurPath; UIPushButton* mButtonOpen; UIPushButton* mButtonCancel; UIPushButton* mButtonUp; - UIListView* mList; + UIPushButton* mButtonNewFolder; + UISelectButton* mButtonListView; + UISelectButton* mButtonTableView; + UIMultiModelView* mMultiView; UITextInput* mPath; UITextInput* mFile; UIDropDownList* mFiletype; diff --git a/include/eepp/ui/uimenu.hpp b/include/eepp/ui/uimenu.hpp index da02337af..1da270e94 100644 --- a/include/eepp/ui/uimenu.hpp +++ b/include/eepp/ui/uimenu.hpp @@ -32,7 +32,8 @@ class EE_API UIMenu : public UIWidget { UIMenuSeparator* addSeparator(); - UIMenuCheckBox* addCheckBox( const String& text, const bool& active = false ); + UIMenuCheckBox* addCheckBox( const String& text, const bool& active = false, + const String& shortcutText = "" ); UIMenuRadioButton* addRadioButton( const String& text, const bool& active = false ); @@ -99,7 +100,7 @@ class EE_API UIMenu : public UIWidget { bool mResizing; UIWidget* mOwnerNode; Sizei mIconMinSize; - UIMenu* mCurrentSubMenu{nullptr}; + UIMenu* mCurrentSubMenu{ nullptr }; Clock mInactiveTime; virtual void onSizeChange(); @@ -119,7 +120,8 @@ class EE_API UIMenu : public UIWidget { UIMenuItem* createMenuItem( const String& text, Drawable* icon, const String& shortcutText = "" ); - UIMenuCheckBox* createMenuCheckBox( const String& text, const bool& active ); + UIMenuCheckBox* createMenuCheckBox( const String& text, const bool& active, + const String& shortcutText = "" ); UIMenuRadioButton* createMenuRadioButton( const String& text, const bool& active ); diff --git a/include/eepp/ui/uimultimodelview.hpp b/include/eepp/ui/uimultimodelview.hpp new file mode 100644 index 000000000..572183e94 --- /dev/null +++ b/include/eepp/ui/uimultimodelview.hpp @@ -0,0 +1,60 @@ +#ifndef EE_UI_UIMULTIMODELVIEW_HPP +#define EE_UI_UIMULTIMODELVIEW_HPP + +#include +#include +#include + +namespace EE { namespace UI { + +class EE_API UIMultiModelView : public UIStackWidget { + public: + enum ViewMode { List, Table }; + + static UIMultiModelView* New(); + + static UIMultiModelView* NewWithTag( const std::string& tag ); + + const ViewMode& getViewMode() const; + + void setViewMode( const ViewMode& mode ); + + UIAbstractView* getCurrentView() const; + + std::shared_ptr getModel() const; + + void setModel( const std::shared_ptr& model ); + + std::function getOnSelection() const; + + void setOnSelection( const std::function& onSelection ); + + std::function getOnSelectionChange() const; + + void setOnSelectionChange( const std::function& onSelectionChange ); + + ModelSelection& getSelection() { return getCurrentView()->getSelection(); } + + const ModelSelection& getSelection() const { return getCurrentView()->getSelection(); } + + UIListView* getListView() const { return mList; } + + UITableView* getTableView() const { return mTable; } + + void setSelection( const ModelIndex& index, bool scrollToSelection = true ); + + protected: + UIMultiModelView( const std::string& tag ); + + std::shared_ptr mModel; + ViewMode mMode{ List }; + UIListView* mList{ nullptr }; + UITableView* mTable{ nullptr }; + + std::function mOnSelectionChange; + std::function mOnSelection; +}; + +}} // namespace EE::UI + +#endif // EE_UI_UIMULTIMODELVIEW_HPP diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index b6634d81d..1ceb35db9 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -259,6 +259,10 @@ class EE_API UINode : public Node { virtual void nodeDraw(); + void clearForeground(); + + void clearBackground(); + protected: Vector2f mDpPos; Sizef mDpSize; diff --git a/include/eepp/ui/uiscrollablewidget.hpp b/include/eepp/ui/uiscrollablewidget.hpp index 21f15474f..c658939e5 100644 --- a/include/eepp/ui/uiscrollablewidget.hpp +++ b/include/eepp/ui/uiscrollablewidget.hpp @@ -51,6 +51,8 @@ class EE_API UIScrollableWidget : public UIWidget { virtual Rectf getVisibleRect() const; + bool shouldVerticalScrollBeVisible() const; + protected: ScrollViewType mViewType; ScrollBarMode mVScrollMode; diff --git a/include/eepp/ui/uistackwidget.hpp b/include/eepp/ui/uistackwidget.hpp new file mode 100644 index 000000000..ab4954505 --- /dev/null +++ b/include/eepp/ui/uistackwidget.hpp @@ -0,0 +1,30 @@ +#ifndef EE_UI_UISTACKWIDGET_HPP +#define EE_UI_UISTACKWIDGET_HPP + +#include + +namespace EE { namespace UI { + +class EE_API UIStackWidget : public UIWidget { + public: + static UIStackWidget* New(); + + static UIStackWidget* NewWithTag( const std::string& tag = "stackwidget" ); + + void setActiveWidget( UIWidget* widget ); + + UIWidget* getActiveWidget() const; + + protected: + UIWidget* mActiveWidget{ nullptr }; + + UIStackWidget( const std::string& tag = "stackwidget" ); + + virtual void onSizeChange(); + + virtual void onChildCountChange( Node* child, const bool& removed ); +}; + +}} // namespace EE::UI + +#endif // EE_UI_UISTACKWIDGET_HPP diff --git a/include/eepp/ui/uitableview.hpp b/include/eepp/ui/uitableview.hpp index f25eb1aed..588791e78 100644 --- a/include/eepp/ui/uitableview.hpp +++ b/include/eepp/ui/uitableview.hpp @@ -23,7 +23,7 @@ class EE_API UITableView : public UIAbstractTableView { virtual ModelIndex findRowWithText( const std::string& text, const bool& caseSensitive = false, - const bool& exactMatch = false ); + const bool& exactMatch = false ) const; protected: Sizef mContentSize; diff --git a/include/eepp/ui/uitreeview.hpp b/include/eepp/ui/uitreeview.hpp index 8c4c75ea8..9d9dd611e 100644 --- a/include/eepp/ui/uitreeview.hpp +++ b/include/eepp/ui/uitreeview.hpp @@ -126,7 +126,7 @@ class EE_API UITreeView : public UIAbstractTableView { void setExpanderIconSize( const size_t& expanderSize ); virtual ModelIndex findRowWithText( const std::string& text, const bool& caseSensitive = false, - const bool& exactMatch = false ); + const bool& exactMatch = false ) const; protected: enum class IterationDecision { diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index 63223faf2..dfc88af2e 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -55,12 +55,24 @@ true true true + *.md, *.MD, Makefile true + true ProjectExplorer.Project.PluginSettings + + true + true + true + true + true + + + 0 + true true Builtin.Questionable @@ -84,6 +96,7 @@ ProjectExplorer.Project.Target.0 + Desktop Desktop Desktop {6d057187-158a-4883-8d5b-d470a6b6b025} @@ -130,6 +143,7 @@ 2 false + debug-test GenericProjectManager.GenericBuildConfiguration @@ -167,6 +181,7 @@ 2 false + release-test GenericProjectManager.GenericBuildConfiguration @@ -210,6 +225,7 @@ 2 false + debug-all GenericProjectManager.GenericBuildConfiguration @@ -253,6 +269,7 @@ 2 false + release-all GenericProjectManager.GenericBuildConfiguration @@ -289,6 +306,7 @@ 2 false + debug-win-all GenericProjectManager.GenericBuildConfiguration @@ -325,6 +343,7 @@ 2 false + release-win-all GenericProjectManager.GenericBuildConfiguration @@ -361,6 +380,7 @@ 2 false + debug-sound GenericProjectManager.GenericBuildConfiguration @@ -397,6 +417,7 @@ 2 false + debug-sprites GenericProjectManager.GenericBuildConfiguration @@ -433,6 +454,7 @@ 2 false + debug-fonts GenericProjectManager.GenericBuildConfiguration @@ -469,6 +491,7 @@ 2 false + debug-vbo-fbo-batch GenericProjectManager.GenericBuildConfiguration @@ -505,6 +528,7 @@ 2 false + debug-physics GenericProjectManager.GenericBuildConfiguration @@ -541,6 +565,7 @@ 2 false + debug-http-request GenericProjectManager.GenericBuildConfiguration @@ -578,6 +603,7 @@ 2 false + debug-static-lib GenericProjectManager.GenericBuildConfiguration @@ -621,6 +647,7 @@ 2 false + debug-eeiv GenericProjectManager.GenericBuildConfiguration @@ -657,6 +684,7 @@ 2 false + debug-ui-hello-world GenericProjectManager.GenericBuildConfiguration @@ -694,6 +722,7 @@ 2 false + release-static-lib GenericProjectManager.GenericBuildConfiguration @@ -731,6 +760,7 @@ 2 false + debug-dynamic-lib GenericProjectManager.GenericBuildConfiguration @@ -768,6 +798,7 @@ 2 false + release-dynamic-lib GenericProjectManager.GenericBuildConfiguration @@ -813,6 +844,7 @@ 2 false + debug-ew GenericProjectManager.GenericBuildConfiguration @@ -851,6 +883,7 @@ 2 false + release-ew GenericProjectManager.GenericBuildConfiguration @@ -889,6 +922,7 @@ 2 false + debug-es GenericProjectManager.GenericBuildConfiguration @@ -927,6 +961,7 @@ 2 false + release-es GenericProjectManager.GenericBuildConfiguration @@ -1005,6 +1040,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-test-debug @@ -1081,6 +1117,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-test @@ -1157,6 +1194,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-physics-debug @@ -1233,6 +1271,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-http-request-debug @@ -1309,6 +1348,7 @@ 13 14 + 2 %{buildDir}../../../bin/eeiv-debug @@ -1385,6 +1425,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-TextureAtlasEditor-debug @@ -1461,6 +1502,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-MapEditor-debug @@ -1537,6 +1579,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-UIEditor-debug @@ -1613,6 +1656,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-ui-hello-world-debug @@ -1689,6 +1733,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-TexturePacker-debug @@ -1765,6 +1810,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-ui-perf-test-debug @@ -1841,6 +1887,7 @@ 13 14 + 2 %{buildDir}../../../bin/ecode-debug @@ -1917,6 +1964,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-empty-window-debug @@ -1993,6 +2041,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-empty-window @@ -2069,6 +2118,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-external-shader-debug @@ -2145,6 +2195,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-external-shader @@ -2221,6 +2272,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-sound-debug @@ -2297,6 +2349,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-sprites-debug @@ -2373,6 +2426,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-fonts-debug @@ -2449,6 +2503,7 @@ 13 14 + 2 %{buildDir}../../../bin/eepp-vbo-fbo-batch-debug @@ -2473,6 +2528,7 @@ ProjectExplorer.Project.Target.1 + Desktop Imported Kit Imported Kit {c0864b34-7205-4013-af48-71ab04d386b1} @@ -2517,6 +2573,7 @@ 2 false + Default GenericProjectManager.GenericBuildConfiguration @@ -2594,6 +2651,7 @@ 13 14 + 2 diff --git a/projects/linux/ee.files b/projects/linux/ee.files index cae6bdc8c..61e4df193 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -380,6 +380,7 @@ ../../include/eepp/ui/uimenuseparator.hpp ../../include/eepp/ui/uimenusubmenu.hpp ../../include/eepp/ui/uimessagebox.hpp +../../include/eepp/ui/uimultimodelview.hpp ../../include/eepp/ui/uinode.hpp ../../include/eepp/ui/uinodedrawable.hpp ../../include/eepp/ui/uipopupmenu.hpp @@ -398,6 +399,7 @@ ../../include/eepp/ui/uispinbox.hpp ../../include/eepp/ui/uisplitter.hpp ../../include/eepp/ui/uisprite.hpp +../../include/eepp/ui/uistackwidget.hpp ../../include/eepp/ui/uistate.hpp ../../include/eepp/ui/uistyle.hpp ../../include/eepp/ui/uitab.hpp @@ -854,6 +856,7 @@ ../../src/eepp/ui/uimenuseparator.cpp ../../src/eepp/ui/uimenusubmenu.cpp ../../src/eepp/ui/uimessagebox.cpp +../../src/eepp/ui/uimultimodelview.cpp ../../src/eepp/ui/uinode.cpp ../../src/eepp/ui/uinodedrawable.cpp ../../src/eepp/ui/uipopupmenu.cpp @@ -872,6 +875,7 @@ ../../src/eepp/ui/uispinbox.cpp ../../src/eepp/ui/uisplitter.cpp ../../src/eepp/ui/uisprite.cpp +../../src/eepp/ui/uistackwidget.cpp ../../src/eepp/ui/uistate.cpp ../../src/eepp/ui/uistyle.cpp ../../src/eepp/ui/uitab.cpp diff --git a/projects/linux/ee.includes b/projects/linux/ee.includes index 4292a5f8a..0be4a23df 100644 --- a/projects/linux/ee.includes +++ b/projects/linux/ee.includes @@ -9,3 +9,4 @@ ../../include/eepp/ui/tools ../../include/eepp/ui ../../src/eepp/ui +/usr/lib64/gcc/x86_64-suse-linux/10/include diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index 272109847..aecbaecab 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1523,6 +1523,10 @@ bool Node::hasFocus() const { return 0 != ( mNodeFlags & NODE_FLAG_HAS_FOCUS ); } +bool Node::hasFocusWithin() const { + return hasFocus() || inParentTreeOf( getEventDispatcher()->getFocusNode() ); +} + void Node::setFocus() {} Node* Node::getFirstWidget() const { diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index 1d1f7f607..740522446 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -216,6 +216,8 @@ void UIAbstractTableView::updateColumnsWidth() { int col = 0; if ( visibleColumnCount() == 1 && ( col = visibleColumn() ) != -1 ) { Float width = eemax( getContentSpaceWidth(), getMaxColumnContentWidth( col ) ); + if ( shouldVerticalScrollBeVisible() ) + width -= getVerticalScrollBar()->getPixelsSize().getWidth(); columnData( col ).width = width; updateHeaderSize(); onColumnSizeChange( col ); @@ -310,7 +312,7 @@ UITableRow* UIAbstractTableView::updateRow( const int& rowIndex, const ModelInde } rowWidget->setCurIndex( index ); rowWidget->setPixelsSize( getContentSize().getWidth(), getRowHeight() ); - rowWidget->setPixelsPosition( {-mScrollOffset.x, yOffset - mScrollOffset.y} ); + rowWidget->setPixelsPosition( { -mScrollOffset.x, yOffset - mScrollOffset.y } ); if ( getSelection().contains( index ) ) { rowWidget->pushState( UIState::StateSelected ); } else { @@ -353,7 +355,7 @@ UIWidget* UIAbstractTableView::updateCell( const int& rowIndex, const ModelIndex widget->reloadStyle( true, true, true ); } widget->setPixelsSize( columnData( index.column() ).width, getRowHeight() ); - widget->setPixelsPosition( {getColumnPosition( index.column() ).x, 0} ); + widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } ); if ( widget->isType( UI_TYPE_TABLECELL ) ) { UITableCell* cell = widget->asType(); cell->setCurIndex( index ); @@ -401,8 +403,8 @@ void UIAbstractTableView::setSelection( const ModelIndex& index, bool scrollToSe auto& model = *this->getModel(); if ( model.isValid( index ) && scrollToSelection ) { getSelection().set( index ); - scrollToPosition( {{mScrollOffset.x, getHeaderHeight() + index.row() * getRowHeight()}, - {columnData( index.column() ).width, getRowHeight()}} ); + scrollToPosition( { { mScrollOffset.x, getHeaderHeight() + index.row() * getRowHeight() }, + { columnData( index.column() ).width, getRowHeight() } } ); } } @@ -436,6 +438,7 @@ void UIAbstractTableView::onSortColumn( const size_t& colIndex ) { columnData( model->keyColumn() ).widget ) { UIImage* image = columnData( model->keyColumn() ).widget->getExtraInnerWidget()->asType(); + image->setForegroundFillEnabled( false ); image->setDrawable( nullptr ); } SortOrder sortOrder = model->sortOrder() == SortOrder::Ascending ? SortOrder::Descending @@ -444,7 +447,10 @@ void UIAbstractTableView::onSortColumn( const size_t& colIndex ) { UIImage* image = button->getExtraInnerWidget()->asType(); std::string tag = button->getElementTag() + "::arrow"; image->setElementTag( sortOrder == SortOrder::Ascending ? tag + "-up" : tag + "-down" ); + image->setForegroundFillEnabled( true ); image->reloadStyle(); + if ( image->getForeground() ) + image->getForeground()->setAlpha( 255 ); if ( image && image->getForeground() == nullptr ) { Drawable* icon = mUISceneNode->findIconDrawable( sortOrder == SortOrder::Ascending ? "arrow-down" : "arrow-up", mSortIconSize ); @@ -474,10 +480,6 @@ Uint32 UIAbstractTableView::onTextInput( const TextInputEvent& event ) { return 1; } -ModelIndex UIAbstractTableView::findRowWithText( const std::string&, const bool&, const bool& ) { - return {}; -} - bool UIAbstractTableView::applyProperty( const StyleSheetProperty& attribute ) { if ( !checkPropertyDefinition( attribute ) ) return false; diff --git a/src/eepp/ui/abstract/uiabstractview.cpp b/src/eepp/ui/abstract/uiabstractview.cpp index f6e9633a1..d2419fde6 100644 --- a/src/eepp/ui/abstract/uiabstractview.cpp +++ b/src/eepp/ui/abstract/uiabstractview.cpp @@ -63,4 +63,8 @@ void UIAbstractView::notifySelectionChange() { mOnSelectionChange(); } +ModelIndex UIAbstractView::findRowWithText( const std::string&, const bool&, const bool& ) const { + return {}; +} + }}} // namespace EE::UI::Abstract diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 9258bd14a..a8e4fd9d6 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -797,7 +797,7 @@ Uint32 UICodeEditor::onMouseClick( const Vector2i& position, const Uint32& flags if ( ( flags & EE_BUTTON_LMASK ) && mLastDoubleClick.getElapsedTime() < Milliseconds( 300.f ) ) { mDoc->selectLine(); - } else if ( flags & EE_BUTTON_MMASK ) { + } else if ( ( flags & EE_BUTTON_MMASK ) && isMouseOverMeOrChilds() ) { auto txt( getUISceneNode()->getWindow()->getClipboard()->getText() ); if ( !txt.empty() ) { if ( mDoc->hasSelection() ) { diff --git a/src/eepp/ui/uifiledialog.cpp b/src/eepp/ui/uifiledialog.cpp index 0ca78c31f..039d151bc 100644 --- a/src/eepp/ui/uifiledialog.cpp +++ b/src/eepp/ui/uifiledialog.cpp @@ -1,9 +1,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -84,18 +86,64 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) ->setParent( hLayout ); - mList = UIListView::New(); - mList->setParent( linearLayout ); - mList->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ) + mButtonNewFolder = UIPushButton::New(); + mButtonNewFolder->setText( "New Folder" ) + ->setLayoutMarginLeft( 4 ) + ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) + ->setParent( hLayout ); + mButtonNewFolder->addEventListener( Event::MouseClick, [&]( const Event* event ) { + const MouseEvent* mouseEvent = static_cast( event ); + if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) { + UIMessageBox* msgBox = + UIMessageBox::New( UIMessageBox::INPUT, "Enter new folder name:" ); + msgBox->setTitle( "Create new folder" ); + msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); + msgBox->show(); + msgBox->addEventListener( Event::MsgBoxConfirmClick, [&, msgBox]( const Event* ) { + auto folderName( msgBox->getTextInput()->getText() ); + auto newFolderPath( getCurPath() + folderName ); + if ( !FileSystem::fileExists( newFolderPath ) && + FileSystem::makeDir( newFolderPath ) ) { + refreshFolder(); + } + } ); + } + } ); + + mButtonListView = UISelectButton::New(); + mButtonListView->setText( "List" ) + ->setLayoutMarginLeft( 4 ) + ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) + ->setParent( hLayout ); + mButtonListView->addEventListener( Event::MouseClick, [&]( const Event* event ) { + const MouseEvent* mouseEvent = static_cast( event ); + if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) + setViewMode( UIMultiModelView::ViewMode::List ); + } ); + + mButtonTableView = UISelectButton::New(); + mButtonTableView->setText( "Table" ) + ->setLayoutMarginLeft( 4 ) + ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) + ->setParent( hLayout ); + mButtonTableView->addEventListener( Event::MouseClick, [&]( const Event* event ) { + const MouseEvent* mouseEvent = static_cast( event ); + if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) + setViewMode( UIMultiModelView::ViewMode::Table ); + } ); + + mMultiView = UIMultiModelView::New(); + mMultiView->setParent( linearLayout ); + mMultiView->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ) ->setLayoutWeight( 1 ) ->setLayoutMargin( Rectf( 0, 0, 0, 4 ) ); - mList->addEventListener( Event::KeyDown, [&]( const Event* event ) { + mMultiView->addEventListener( Event::KeyDown, [&]( const Event* event ) { const KeyEvent* KEvent = reinterpret_cast( event ); if ( KEvent->getKeyCode() == KEY_BACKSPACE ) { goFolderUp(); } } ); - mList->addEventListener( Event::OnModelEvent, [&]( const Event* event ) { + mMultiView->addEventListener( Event::OnModelEvent, [&]( const Event* event ) { const ModelEvent* modelEvent = static_cast( event ); if ( modelEvent->getModelEventType() == ModelEventType::Open ) { Variant vPath( @@ -114,10 +162,12 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa } } } ); - mList->setOnSelectionChange( [&] { - if ( mList->getSelection().isEmpty() ) + mMultiView->setOnSelectionChange( [&] { + if ( mMultiView->getSelection().isEmpty() ) + return; + auto* node = (FileSystemModel::Node*)mMultiView->getSelection().first().data(); + if ( !node ) return; - auto* node = (FileSystemModel::Node*)mList->getSelection().first().data(); if ( !isSaveDialog() ) { if ( getAllowFolderSelect() || !FileSystem::isDirectory( node->fullPath() ) ) setFileName( node->getName() ); @@ -125,7 +175,6 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa setFileName( node->getName() ); } } ); - mList->setAutoExpandOnSingleColumn( true ); hLayout = UILinearLayout::NewHorizontal(); hLayout->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ) @@ -179,7 +228,12 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa ->setSize( 80, 0 ) ->setParent( hLayout ); - mList->setFocus(); + mMultiView->getCurrentView()->setFocus(); + mMultiView->getListView()->setColumnsVisible( { FileSystemModel::Name } ); + mMultiView->getTableView()->setColumnsVisible( + { FileSystemModel::Name, FileSystemModel::Size, FileSystemModel::ModificationTime } ); + + setViewMode( UIMultiModelView::ViewMode::List ); applyDefaultTheme(); @@ -206,22 +260,39 @@ void UIFileDialog::setTheme( UITheme* Theme ) { mButtonOpen->setTheme( Theme ); mButtonCancel->setTheme( Theme ); mButtonUp->setTheme( Theme ); - mList->setTheme( Theme ); + mMultiView->setTheme( Theme ); mPath->setTheme( Theme ); mFile->setTheme( Theme ); mFiletype->setTheme( Theme ); Drawable* icon = getUISceneNode()->findIconDrawable( "go-up", PixelDensity::dpToPxI( 16 ) ); - - if ( NULL != icon ) { + if ( icon ) { mButtonUp->setText( "" ); mButtonUp->setIcon( icon ); } + icon = getUISceneNode()->findIconDrawable( "folder-add", PixelDensity::dpToPxI( 16 ) ); + if ( icon ) { + mButtonNewFolder->setText( "" ); + mButtonNewFolder->setIcon( icon ); + } + + icon = getUISceneNode()->findIconDrawable( "list-view", PixelDensity::dpToPxI( 16 ) ); + if ( icon ) { + mButtonListView->setText( "" ); + mButtonListView->setIcon( icon ); + } + + icon = getUISceneNode()->findIconDrawable( "table-view", PixelDensity::dpToPxI( 16 ) ); + if ( icon ) { + mButtonTableView->setText( "" ); + mButtonTableView->setIcon( icon ); + } + onThemeLoaded(); } -void UIFileDialog::refreshFolder() { +void UIFileDialog::refreshFolder( bool resetScroll ) { FileSystem::dirAddSlashAtEnd( mCurPath ); std::vector flist = FileSystem::filesGetInPath( String( mCurPath ), getSortAlphabetically(), getFoldersFirst(), !getShowHidden() ); @@ -235,26 +306,27 @@ void UIFileDialog::refreshFolder() { patterns[i] = FileSystem::fileExtension( String::trim( patterns[i] ) ); } - mList->setModel( FileSystemModel::New( + mMultiView->setModel( /*SortingProxyModel::New(*/ FileSystemModel::New( mCurPath, getShowOnlyFolders() ? FileSystemModel::Mode::DirectoriesOnly : FileSystemModel::Mode::FilesAndDirectories, FileSystemModel::DisplayConfig( getSortAlphabetically(), getFoldersFirst(), - !getShowHidden(), patterns ) ) ); - - mList->setColumnsVisible( { FileSystemModel::Name } ); - mList->setHeadersVisible( false ); + !getShowHidden(), patterns ) ) /*)*/ ); updateClickStep(); - mList->setFocus(); + if ( resetScroll ) + mMultiView->getCurrentView()->scrollToTop(); + + mMultiView->getCurrentView()->setFocus(); } void UIFileDialog::updateClickStep() { - if ( NULL != mList->getVerticalScrollBar() ) { - mList->getVerticalScrollBar()->setClickStep( - 1.f / ( ( mList->getModel()->rowCount() * mList->getRowHeight() ) / - (Float)mList->getSize().getHeight() ) ); + if ( NULL != mMultiView->getListView()->getVerticalScrollBar() ) { + mMultiView->getListView()->getVerticalScrollBar()->setClickStep( + 1.f / + ( ( mMultiView->getModel()->rowCount() * mMultiView->getListView()->getRowHeight() ) / + (Float)mMultiView->getListView()->getSize().getHeight() ) ); } } @@ -264,7 +336,7 @@ void UIFileDialog::setCurPath( const std::string& path ) { mPath->setText( mCurPath ); if ( !isSaveDialog() ) mFile->setText( "" ); - refreshFolder(); + refreshFolder( true ); } void UIFileDialog::openSaveClick() { @@ -295,10 +367,11 @@ void UIFileDialog::disableButtons() { } void UIFileDialog::openFileOrFolder( bool shouldOpenFolder = false ) { - if ( mList->getSelection().isEmpty() ) + if ( mMultiView->getSelection().isEmpty() ) + return; + auto* node = (FileSystemModel::Node*)mMultiView->getSelection().first().data(); + if ( !node ) return; - auto* node = (FileSystemModel::Node*)mList->getSelection().first().data(); - std::string newPath = mCurPath + node->getName(); if ( FileSystem::isDirectory( newPath ) ) { @@ -315,9 +388,9 @@ void UIFileDialog::openFileOrFolder( bool shouldOpenFolder = false ) { void UIFileDialog::goFolderUp() { std::string prevFolderName( FileSystem::fileNameFromPath( mCurPath ) ); setCurPath( FileSystem::removeLastFolderFromPath( mCurPath ) ); - ModelIndex index = mList->findRowWithText( prevFolderName ); + ModelIndex index = mMultiView->getCurrentView()->findRowWithText( prevFolderName ); if ( index.isValid() ) - mList->setSelection( index ); + mMultiView->setSelection( index ); } Uint32 UIFileDialog::onMessage( const NodeMessage* Msg ) { @@ -367,12 +440,12 @@ void UIFileDialog::save() { } void UIFileDialog::open() { - if ( mList->getSelection().isEmpty() && + if ( mMultiView->getSelection().isEmpty() && !( getAllowFolderSelect() && FileSystem::isDirectory( getFullPath() ) ) ) return; - auto* node = !mList->getSelection().isEmpty() - ? (FileSystemModel::Node*)mList->getSelection().first().data() + auto* node = !mMultiView->getSelection().isEmpty() + ? (FileSystemModel::Node*)mMultiView->getSelection().first().data() : nullptr; if ( ( node && "" != node->getName() ) || getAllowFolderSelect() ) { @@ -474,9 +547,9 @@ std::string UIFileDialog::getCurPath() const { std::string UIFileDialog::getCurFile() const { if ( mDialogFlags & SaveDialog ) return mFile->getText(); - if ( mList->getSelection().isEmpty() ) + if ( mMultiView->getSelection().isEmpty() ) return ""; - auto* node = (FileSystemModel::Node*)mList->getSelection().first().data(); + auto* node = (FileSystemModel::Node*)mMultiView->getSelection().first().data(); return node->getName(); } @@ -492,8 +565,8 @@ UIPushButton* UIFileDialog::getButtonUp() const { return mButtonUp; } -UIListView* UIFileDialog::getList() const { - return mList; +UIMultiModelView* UIFileDialog::getMultiView() const { + return mMultiView; } UITextInput* UIFileDialog::getPathInput() const { @@ -532,4 +605,23 @@ void UIFileDialog::setCloseShortcut( const KeyBindings::Shortcut& closeWithKey ) mCloseShortcut = closeWithKey; } +void UIFileDialog::setViewMode( const UIMultiModelView::ViewMode& viewMode ) { + mMultiView->setViewMode( viewMode ); + switch ( viewMode ) { + case UIMultiModelView::ViewMode::Table: + mButtonTableView->select(); + mButtonListView->unselect(); + break; + case UIMultiModelView::ViewMode::List: + default: + mButtonTableView->unselect(); + mButtonListView->select(); + break; + } +} + +const UIMultiModelView::ViewMode& UIFileDialog::getViewMode() const { + return mMultiView->getViewMode(); +} + }} // namespace EE::UI diff --git a/src/eepp/ui/uimenu.cpp b/src/eepp/ui/uimenu.cpp index 586468127..0e2f6eea9 100644 --- a/src/eepp/ui/uimenu.cpp +++ b/src/eepp/ui/uimenu.cpp @@ -74,19 +74,22 @@ UIMenuItem* UIMenu::add( const String& text, Drawable* icon, const String& short return menuItem; } -UIMenuCheckBox* UIMenu::createMenuCheckBox( const String& text, const bool& active ) { +UIMenuCheckBox* UIMenu::createMenuCheckBox( const String& text, const bool& active, + const String& shortcutText ) { UIMenuCheckBox* widget = UIMenuCheckBox::New(); widget->setHorizontalAlign( UI_HALIGN_LEFT ); widget->setParent( this ); widget->setIconMinimumSize( mIconMinSize ); widget->setText( text ); + widget->setShortcutText( shortcutText ); if ( active ) widget->setActive( active ); return widget; } -UIMenuCheckBox* UIMenu::addCheckBox( const String& text, const bool& active ) { - UIMenuCheckBox* chkBox = createMenuCheckBox( text, active ); +UIMenuCheckBox* UIMenu::addCheckBox( const String& text, const bool& active, + const String& shortcutText ) { + UIMenuCheckBox* chkBox = createMenuCheckBox( text, active, shortcutText ); add( chkBox ); return chkBox; } @@ -716,11 +719,11 @@ void UIMenu::findBestMenuPos( Vector2f& pos, UIMenu* menu, UIMenu* parent, if ( !qScreen.contains( qPos ) ) { if ( menu->getPixelsSize().getHeight() <= qScreen.getHeight() ) { - pos = {pos.x, eefloor( ( qScreen.getHeight() - - menu->getPixelsSize().getHeight() ) * - 0.5f )}; + pos = { pos.x, eefloor( ( qScreen.getHeight() - + menu->getPixelsSize().getHeight() ) * + 0.5f ) }; } else { - pos = {pos.x, 0}; + pos = { pos.x, 0 }; } } } diff --git a/src/eepp/ui/uimultimodelview.cpp b/src/eepp/ui/uimultimodelview.cpp new file mode 100644 index 000000000..e247ef181 --- /dev/null +++ b/src/eepp/ui/uimultimodelview.cpp @@ -0,0 +1,99 @@ +#include + +namespace EE { namespace UI { + +UIMultiModelView* UIMultiModelView::New() { + return NewWithTag( "multimodelview" ); +} + +UIMultiModelView* UIMultiModelView::NewWithTag( const std::string& tag ) { + return eeNew( UIMultiModelView, ( tag ) ); +} + +UIMultiModelView::UIMultiModelView( const std::string& tag ) : UIStackWidget( tag ) { + auto modelEvent = [&]( const Event* event ) { + const ModelEvent* mevent = static_cast( event ); + sendEvent( mevent ); + }; + auto selectionChange = [&]() { + if ( mOnSelectionChange ) + mOnSelectionChange(); + }; + auto selection = [&]( const ModelIndex& index ) { + if ( mOnSelection ) + mOnSelection( index ); + }; + mList = UIListView::New(); + mTable = UITableView::New(); + mList->setParent( this ); + mTable->setParent( this ); + mList->addEventListener( Event::OnModelEvent, modelEvent ); + mTable->addEventListener( Event::OnModelEvent, modelEvent ); + mList->setOnSelectionChange( selectionChange ); + mTable->setOnSelectionChange( selectionChange ); + mList->setOnSelection( selection ); + mTable->setOnSelection( selection ); + mList->setAutoExpandOnSingleColumn( true ); + setViewMode( List ); +} + +std::shared_ptr UIMultiModelView::getModel() const { + return mModel; +} + +void UIMultiModelView::setModel( const std::shared_ptr& model ) { + mModel = model; + mList->setModel( mModel ); + mTable->setModel( mModel ); +} + +const UIMultiModelView::ViewMode& UIMultiModelView::getViewMode() const { + return mMode; +} + +void UIMultiModelView::setViewMode( const ViewMode& mode ) { + mMode = mode; + switch ( mMode ) { + case Table: + setActiveWidget( mTable ); + break; + case List: + default: + setActiveWidget( mList ); + break; + } +} + +UIAbstractView* UIMultiModelView::getCurrentView() const { + switch ( mMode ) { + case Table: + return mTable; + case List: + default: + return mList; + } +} + +std::function UIMultiModelView::getOnSelection() const { + return mOnSelection; +} + +void UIMultiModelView::setOnSelection( + const std::function& onSelection ) { + mOnSelection = onSelection; +} + +std::function UIMultiModelView::getOnSelectionChange() const { + return mOnSelectionChange; +} + +void UIMultiModelView::setOnSelectionChange( const std::function& onSelectionChange ) { + mOnSelectionChange = onSelectionChange; +} + +void UIMultiModelView::setSelection( const ModelIndex& index, bool scrollToSelection ) { + mList->setSelection( index, scrollToSelection ); + mTable->setSelection( index, scrollToSelection ); +} + +}} // namespace EE::UI diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 4ab9efa02..5e917287e 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -768,6 +768,14 @@ void UINode::nodeDraw() { } } +void UINode::clearForeground() { + eeSAFE_DELETE( mForeground ); +} + +void UINode::clearBackground() { + eeSAFE_DELETE( mBackground ); +} + UINodeDrawable* UINode::getBackground() { if ( NULL == mBackground ) { mBackground = UINodeDrawable::New( this ); diff --git a/src/eepp/ui/uipushbutton.cpp b/src/eepp/ui/uipushbutton.cpp index 55d665c84..6188ae633 100644 --- a/src/eepp/ui/uipushbutton.cpp +++ b/src/eepp/ui/uipushbutton.cpp @@ -94,7 +94,9 @@ void UIPushButton::onAutoSize() { setInternalHeight( getSkinSize().getHeight() ); } - if ( ( mFlags & UI_AUTO_SIZE ) || mWidthPolicy == SizePolicy::WrapContent ) { + if ( mWidthPolicy == SizePolicy::WrapContent ) { + setInternalPixelsWidth( getContentSize().getWidth() ); + } else if ( mFlags & UI_AUTO_SIZE ) { Float minSize = getContentSize().getWidth(); if ( minSize > mSize.getWidth() ) setInternalPixelsWidth( minSize ); @@ -103,7 +105,7 @@ void UIPushButton::onAutoSize() { Vector2f UIPushButton::calcLayoutSize( const std::vector& widgets, const Rectf& padding ) const { - Vector2f totSize{padding.Left, padding.Top + padding.Bottom}; + Vector2f totSize{ padding.Left, padding.Top + padding.Bottom }; UIWidget* widget; for ( size_t i = 0; i < widgets.size(); i++ ) { if ( !widgets[i] || !widgets[i]->isVisible() ) @@ -125,7 +127,7 @@ Vector2f UIPushButton::calcLayoutSize( const std::vector& widgets, Vector2f UIPushButton::packLayout( const std::vector& widgets, const Rectf& padding ) { std::vector pos( widgets.size() ); - Vector2f totSize{padding.Left, padding.Top + padding.Bottom}; + Vector2f totSize{ padding.Left, padding.Top + padding.Bottom }; UIWidget* widget; for ( size_t i = 0; i < widgets.size(); i++ ) { if ( !widgets[i] || !widgets[i]->isVisible() ) @@ -204,13 +206,13 @@ Sizef UIPushButton::updateLayout() { Rectf autoPadding = calculatePadding(); switch ( mInnerWidgetOrientation ) { case InnerWidgetOrientation::Left: - size = packLayout( {getExtraInnerWidget(), mIcon, mTextBox}, autoPadding ); + size = packLayout( { getExtraInnerWidget(), mIcon, mTextBox }, autoPadding ); break; case InnerWidgetOrientation::Center: - size = packLayout( {mIcon, getExtraInnerWidget(), mTextBox}, autoPadding ); + size = packLayout( { mIcon, getExtraInnerWidget(), mTextBox }, autoPadding ); break; case InnerWidgetOrientation::Right: - size = packLayout( {mIcon, mTextBox, getExtraInnerWidget()}, autoPadding ); + size = packLayout( { mIcon, mTextBox, getExtraInnerWidget() }, autoPadding ); break; } return size.ceil(); @@ -248,6 +250,7 @@ UIPushButton* UIPushButton::setIcon( Drawable* icon ) { mIcon->setPixelsSize( icon->getPixelsSize() ); mIcon->setDrawable( icon ); mTextBox->setVisible( !getText().empty() ); + onAutoSize(); updateLayout(); } return this; @@ -261,6 +264,7 @@ UIPushButton* UIPushButton::setText( const String& text ) { if ( text != mTextBox->getText() ) { mTextBox->setVisible( !text.empty() ); mTextBox->setText( text ); + onAutoSize(); updateLayout(); } return this; @@ -347,13 +351,13 @@ Sizef UIPushButton::getContentSize() const { Rectf autoPadding = calculatePadding(); switch ( mInnerWidgetOrientation ) { case InnerWidgetOrientation::Left: - size = calcLayoutSize( {getExtraInnerWidget(), mIcon, mTextBox}, autoPadding ); + size = calcLayoutSize( { getExtraInnerWidget(), mIcon, mTextBox }, autoPadding ); break; case InnerWidgetOrientation::Center: - size = calcLayoutSize( {mIcon, getExtraInnerWidget(), mTextBox}, autoPadding ); + size = calcLayoutSize( { mIcon, getExtraInnerWidget(), mTextBox }, autoPadding ); break; case InnerWidgetOrientation::Right: - size = calcLayoutSize( {mIcon, mTextBox, getExtraInnerWidget()}, autoPadding ); + size = calcLayoutSize( { mIcon, mTextBox, getExtraInnerWidget() }, autoPadding ); break; } if ( getSkin() ) diff --git a/src/eepp/ui/uiscrollablewidget.cpp b/src/eepp/ui/uiscrollablewidget.cpp index 35333becb..c67d78e3d 100644 --- a/src/eepp/ui/uiscrollablewidget.cpp +++ b/src/eepp/ui/uiscrollablewidget.cpp @@ -189,6 +189,12 @@ Rectf UIScrollableWidget::getVisibleRect() const { return Rectf( mScrollOffset, getVisibleArea() ); } +bool UIScrollableWidget::shouldVerticalScrollBeVisible() const { + Float totH = getPixelsSize().getHeight() - getPixelsPadding().Top - getPixelsPadding().Bottom - + mHScroll->getPixelsSize().getHeight(); + return getContentSize().getHeight() > totH; +} + void UIScrollableWidget::updateScroll() { Sizef totalScroll = getScrollableArea(); Vector2f initScroll( mScrollOffset ); diff --git a/src/eepp/ui/uistackwidget.cpp b/src/eepp/ui/uistackwidget.cpp new file mode 100644 index 000000000..e57a35519 --- /dev/null +++ b/src/eepp/ui/uistackwidget.cpp @@ -0,0 +1,80 @@ +#include + +namespace EE { namespace UI { + +UIStackWidget* UIStackWidget::New() { + return NewWithTag( "stackwidget" ); +} + +UIStackWidget* UIStackWidget::NewWithTag( const std::string& tag ) { + return eeNew( UIStackWidget, ( tag ) ); +} + +UIStackWidget::UIStackWidget( const std::string& tag ) : UIWidget( tag ) {} + +void UIStackWidget::setActiveWidget( UIWidget* widget ) { + if ( widget == mActiveWidget ) + return; + + if ( isChild( widget ) ) { + bool activeWidgetHadFocus = mActiveWidget && mActiveWidget->hasFocusWithin(); + + if ( mActiveWidget ) { + mActiveWidget->setVisible( false ); + mActiveWidget->setEnabled( false ); + } + + mActiveWidget = widget; + + if ( mActiveWidget ) { + mActiveWidget->setPixelsSize( mSize ); + + if ( activeWidgetHadFocus ) + mActiveWidget->setFocus(); + + mActiveWidget->setVisible( true ); + mActiveWidget->setEnabled( true ); + } + + sendCommonEvent( Event::OnActiveWidgetChange ); + } +} + +UIWidget* UIStackWidget::getActiveWidget() const { + return mActiveWidget; +} + +void UIStackWidget::onSizeChange() { + UIWidget::onSizeChange(); + if ( mActiveWidget ) + mActiveWidget->setPixelsSize( mSize ); +} + +void UIStackWidget::onChildCountChange( Node* child, const bool& removed ) { + UIWidget::onChildCountChange( child, removed ); + + if ( child && child->isWidget() ) { + UIWidget* widget = child->asType(); + + if ( !removed ) { + if ( nullptr == mActiveWidget ) { + setActiveWidget( widget ); + } else { + widget->setVisible( false ); + widget->setEnabled( false ); + } + } else { + if ( widget == mActiveWidget ) { + Node* newActiveWidget = getFirstWidget(); + if ( newActiveWidget ) { + setActiveWidget( newActiveWidget->asType() ); + } else { + mActiveWidget = nullptr; + sendCommonEvent( Event::OnActiveWidgetChange ); + } + } + } + } +} + +}} // namespace EE::UI diff --git a/src/eepp/ui/uitableview.cpp b/src/eepp/ui/uitableview.cpp index 214c5220e..05e106ee1 100644 --- a/src/eepp/ui/uitableview.cpp +++ b/src/eepp/ui/uitableview.cpp @@ -241,8 +241,8 @@ Uint32 UITableView::onKeyDown( const KeyEvent& event ) { } ModelIndex UITableView::findRowWithText( const std::string& text, const bool& caseSensitive, - const bool& exactMatch ) { - Model* model = getModel(); + const bool& exactMatch ) const { + const Model* model = getModel(); if ( !model || model->rowCount() == 0 ) return {}; size_t rc = model->rowCount(); diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index fc1c66f03..46e50f044 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -35,7 +35,7 @@ UITreeView::MetadataForIndex& UITreeView::getIndexMetadata( const ModelIndex& in if ( it != mViewMetadata.end() ) return it->second; auto newMetadata = MetadataForIndex(); - mViewMetadata.insert( {index.data(), std::move( newMetadata )} ); + mViewMetadata.insert( { index.data(), std::move( newMetadata ) } ); return mViewMetadata[index.data()]; } @@ -170,7 +170,7 @@ UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index, widget->reloadStyle( true, true, true ); } widget->setPixelsSize( columnData( index.column() ).width, getRowHeight() ); - widget->setPixelsPosition( {getColumnPosition( index.column() ).x, 0} ); + widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } ); if ( widget->isType( UI_TYPE_TABLECELL ) ) { UITableCell* cell = widget->asType(); @@ -432,7 +432,7 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { Float curY; traverseTree( [&]( const int&, const ModelIndex& index, const size_t&, const Float& offsetY ) { - deque.push_back( {index, offsetY} ); + deque.push_back( { index, offsetY } ); if ( (int)deque.size() > pageSize ) deque.pop_front(); if ( index == curIndex ) @@ -442,8 +442,8 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { curY = deque.front().second - getHeaderHeight(); getSelection().set( deque.front().first ); scrollToPosition( - {{mScrollOffset.x, curY}, - {columnData( deque.front().first.column() ).width, getRowHeight()}} ); + { { mScrollOffset.x, curY }, + { columnData( deque.front().first.column() ).width, getRowHeight() } } ); return 1; } case KEY_PAGEDOWN: { @@ -478,8 +478,8 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { } curY += getRowHeight(); getSelection().set( foundIndex ); - scrollToPosition( {{mScrollOffset.x, curY}, - {columnData( foundIndex.column() ).width, getRowHeight()}} ); + scrollToPosition( { { mScrollOffset.x, curY }, + { columnData( foundIndex.column() ).width, getRowHeight() } } ); return 1; } case KEY_UP: { @@ -609,8 +609,8 @@ void UITreeView::onSortColumn( const size_t& ) { } ModelIndex UITreeView::findRowWithText( const std::string& text, const bool& caseSensitive, - const bool& exactMatch ) { - Model* model = getModel(); + const bool& exactMatch ) const { + const Model* model = getModel(); if ( !model || model->rowCount() == 0 ) return {}; ModelIndex foundIndex = {}; diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 1a41539bd..61d7f4539 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,7 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["treeview"] = UITreeView::New; registeredWidget["tableview"] = UITableView::New; registeredWidget["listview"] = UIListView::New; + registeredWidget["stackwidget"] = UIStackWidget::New; registeredWidget["hbox"] = UILinearLayout::NewHorizontal; registeredWidget["vbox"] = UILinearLayout::NewVertical; diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index d318ed63c..6d3721493 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -174,10 +174,11 @@ void App::openFontDialog( std::string& fontPath ) { absoluteFontPath = mResPath + fontPath; UIFileDialog* dialog = UIFileDialog::New( UIFileDialog::DefaultFlags, "*.ttf; *.otf; *.wolff", FileSystem::fileRemoveFileName( absoluteFontPath ) ); - ModelIndex index = - dialog->getList()->findRowWithText( FileSystem::fileNameFromPath( fontPath ), true, true ); + ModelIndex index = dialog->getMultiView()->getListView()->findRowWithText( + FileSystem::fileNameFromPath( fontPath ), true, true ); if ( index.isValid() ) - dialog->getList()->setSelection( index ); + dialog->runOnMainThread( + [&, dialog, index]() { dialog->getMultiView()->setSelection( index ); } ); dialog->setWinFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_MAXIMIZE_BUTTON | UI_WIN_MODAL ); dialog->setTitle( "Select Font File" ); dialog->setCloseShortcut( KEY_ESCAPE ); @@ -187,9 +188,17 @@ void App::openFontDialog( std::string& fontPath ) { newPath = newPath.substr( mResPath.size() ); if ( fontPath != newPath ) { fontPath = newPath; - UIMessageBox::New( UIMessageBox::OK, - "You will need to restart the editor to see font changes." ) - ->show(); + auto fontName = + FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( fontPath ) ); + FontTrueType* fontMono = loadFont( fontName, fontPath ); + if ( fontMono ) { + mFontMono = fontMono; + mFontMono->setBoldAdvanceSameAsRegular( true ); + if ( mEditorSplitter ) { + mEditorSplitter->forEachEditor( + [&]( UICodeEditor* editor ) { editor->setFont( mFontMono ); } ); + } + } } } ); dialog->addEventListener( Event::OnWindowClose, [&]( const Event* ) { @@ -1012,6 +1021,14 @@ void App::showSidePanel( bool show ) { } } +void App::switchSidePanel() { + mConfig.ui.showSidePanel = !mConfig.ui.showSidePanel; + mWindowMenu->getItem( "Show Left Sidebar" ) + ->asType() + ->setActive( mConfig.ui.showSidePanel ); + showSidePanel( mConfig.ui.showSidePanel ); +} + UIMenu* App::createWindowMenu() { mWindowMenu = UIPopUpMenu::New(); mWindowMenu->add( "UI Scale Factor (Pixel Density)", findIcon( "pixel-density" ) ); @@ -1020,10 +1037,10 @@ UIMenu* App::createWindowMenu() { mWindowMenu->add( "Serif Font...", findIcon( "font-size" ) ); mWindowMenu->add( "Monospace Font...", findIcon( "font-size" ) ); mWindowMenu->addSeparator(); - mWindowMenu->addCheckBox( "Full Screen Mode" ) - ->setShortcutText( getKeybind( "fullscreen-toggle" ) ) + mWindowMenu->addCheckBox( "Full Screen Mode", false, getKeybind( "fullscreen-toggle" ) ) ->setId( "fullscreen-mode" ); - mWindowMenu->addCheckBox( "Show Side Panel" )->setActive( mConfig.ui.showSidePanel ); + mWindowMenu->addCheckBox( "Show Left Sidebar", mConfig.ui.showSidePanel, + getKeybind( "switch-side-panel" ) ); mWindowMenu->addSeparator(); mWindowMenu->add( "Split Left", findIcon( "split-horizontal" ), getKeybind( "split-left" ) ); mWindowMenu->add( "Split Right", findIcon( "split-horizontal" ), getKeybind( "split-right" ) ); @@ -1037,7 +1054,7 @@ UIMenu* App::createWindowMenu() { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); - if ( item->getText() == "Show Side Panel" ) { + if ( item->getText() == "Show Left Sidebar" ) { mConfig.ui.showSidePanel = item->asType()->isActive(); showSidePanel( mConfig.ui.showSidePanel ); } else if ( item->getText() == "UI Scale Factor (Pixel Density)" ) { @@ -1624,28 +1641,28 @@ std::map App::getDefaultKeybindings() { } std::map App::getLocalKeybindings() { - return { - { { KEY_RETURN, KEYMOD_LALT }, "fullscreen-toggle" }, - { { KEY_F3, KEYMOD_NONE }, "repeat-find" }, - { { KEY_F12, KEYMOD_NONE }, "console-toggle" }, - { { KEY_F, KEYMOD_CTRL }, "find-replace" }, - { { KEY_Q, KEYMOD_CTRL }, "close-app" }, - { { KEY_O, KEYMOD_CTRL }, "open-file" }, - { { KEY_O, KEYMOD_CTRL | KEYMOD_SHIFT }, "open-folder" }, - { { KEY_F6, KEYMOD_NONE }, "debug-draw-highlight-toggle" }, - { { KEY_F7, KEYMOD_NONE }, "debug-draw-boxes-toggle" }, - { { KEY_F8, KEYMOD_NONE }, "debug-draw-debug-data" }, - { { KEY_K, KEYMOD_CTRL }, "open-locatebar" }, - { { KEY_F, KEYMOD_CTRL | KEYMOD_SHIFT }, "open-global-search" }, - { { KEY_L, KEYMOD_CTRL }, "go-to-line" }, - { { KEY_M, KEYMOD_CTRL }, "menu-toggle" }, - { { KEY_S, KEYMOD_CTRL | KEYMOD_SHIFT }, "save-all" }, - }; + return { { { KEY_RETURN, KEYMOD_LALT }, "fullscreen-toggle" }, + { { KEY_F3, KEYMOD_NONE }, "repeat-find" }, + { { KEY_F12, KEYMOD_NONE }, "console-toggle" }, + { { KEY_F, KEYMOD_CTRL }, "find-replace" }, + { { KEY_Q, KEYMOD_CTRL }, "close-app" }, + { { KEY_O, KEYMOD_CTRL }, "open-file" }, + { { KEY_O, KEYMOD_CTRL | KEYMOD_SHIFT }, "open-folder" }, + { { KEY_F6, KEYMOD_NONE }, "debug-draw-highlight-toggle" }, + { { KEY_F7, KEYMOD_NONE }, "debug-draw-boxes-toggle" }, + { { KEY_F8, KEYMOD_NONE }, "debug-draw-debug-data" }, + { { KEY_K, KEYMOD_CTRL }, "open-locatebar" }, + { { KEY_F, KEYMOD_CTRL | KEYMOD_SHIFT }, "open-global-search" }, + { { KEY_L, KEYMOD_CTRL }, "go-to-line" }, + { { KEY_M, KEYMOD_CTRL }, "menu-toggle" }, + { { KEY_S, KEYMOD_CTRL | KEYMOD_SHIFT }, "save-all" }, + { { KEY_F9, KEYMOD_LALT }, "switch-side-panel" } }; } std::vector App::getUnlockedCommands() { - return { "fullscreen-toggle", "open-file", "open-folder", "console-toggle", - "close-app", "open-locatebar", "open-global-search", "menu-toggle" }; + return { "fullscreen-toggle", "open-file", "open-folder", + "console-toggle", "close-app", "open-locatebar", + "open-global-search", "menu-toggle", "switch-side-panel" }; } void App::closeEditors() { @@ -1692,6 +1709,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { editor->setHighlightSelectionMatch( config.highlightSelectionMatch ); editor->setEnableColorPickerOnSelection( config.colorPickerSelection ); editor->setColorPreview( config.colorPreview ); + editor->setFont( mFontMono ); doc.setAutoCloseBrackets( !mConfig.editor.autoCloseBrackets.empty() ); doc.setAutoCloseBracketsPairs( makeAutoClosePairs( mConfig.editor.autoCloseBrackets ) ); doc.setAutoDetectIndentType( config.autoDetectIndentType ); @@ -1761,6 +1779,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { doc.setCommand( "go-to-line", [&] { goToLine(); } ); doc.setCommand( "load-current-dir", [&] { loadCurrentDirectory(); } ); doc.setCommand( "menu-toggle", [&] { toggleSettingsMenu(); } ); + doc.setCommand( "switch-side-panel", [&] { switchSidePanel(); } ); editor->addEventListener( Event::OnSave, [&]( const Event* event ) { UICodeEditor* editor = event->getNode()->asType(); if ( editor->getDocument().getFilePath() == mKeybindingsPath ) { @@ -2134,17 +2153,16 @@ void App::init( const std::string& file, const Float& pidelDensity ) { mUISceneNode = UISceneNode::New(); - FontTrueType* font = - loadFont( "sans-serif", mConfig.ui.serifFont, "assets/fonts/NotoSans-Regular.ttf" ); - FontTrueType* fontMono = + mFont = loadFont( "sans-serif", mConfig.ui.serifFont, "assets/fonts/NotoSans-Regular.ttf" ); + mFontMono = loadFont( "monospace", mConfig.ui.monospaceFont, "assets/fonts/DejaVuSansMono.ttf" ); - if ( fontMono ) - fontMono->setBoldAdvanceSameAsRegular( true ); + if ( mFontMono ) + mFontMono->setBoldAdvanceSameAsRegular( true ); FontTrueType* iconFont = FontTrueType::New( "icon", mResPath + "assets/fonts/remixicon.ttf" ); - if ( !font || !fontMono || !iconFont ) { + if ( !mFont || !mFontMono || !iconFont ) { printf( "Font not found!" ); return; } @@ -2152,14 +2170,14 @@ void App::init( const std::string& file, const Float& pidelDensity ) { SceneManager::instance()->add( mUISceneNode ); UITheme* theme = - UITheme::load( "uitheme", "uitheme", "", font, mResPath + "assets/ui/breeze.css" ); + UITheme::load( "uitheme", "uitheme", "", mFont, mResPath + "assets/ui/breeze.css" ); theme->setDefaultFontSize( mConfig.ui.fontSize.asDp( 0, Sizef(), mDisplayDPI ) ); mUISceneNode->setStyleSheet( theme->getStyleSheet() ); mUISceneNode ->getUIThemeManager() //->setDefaultEffectsEnabled( true ) ->setDefaultTheme( theme ) - ->setDefaultFont( font ) + ->setDefaultFont( mFont ) ->setDefaultFontSize( mConfig.ui.fontSize.asDp( 0, Sizef(), mDisplayDPI ) ) ->add( theme ); @@ -2337,6 +2355,8 @@ void App::init( const std::string& file, const Float& pidelDensity ) { { "color-picker", 0xf13d }, { "pixel-density", 0xed8c }, { "go-to-line", 0xf1f8 }, + { "table-view", 0xf1de }, + { "list-view", 0xecf1 }, }; for ( auto icon : icons ) iconTheme->add( UIGlyphIcon::New( icon.first, iconFont, icon.second ) ); @@ -2383,7 +2403,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { mEditorSplitter->createEditorWithTabWidget( mBaseLayout ); - mConsole = eeNew( Console, ( fontMono, true, true, 1024 * 1000, 0, mWindow ) ); + mConsole = eeNew( Console, ( mFontMono, true, true, 1024 * 1000, 0, mWindow ) ); initProjectTreeView( file ); diff --git a/src/tools/codeeditor/codeeditor.hpp b/src/tools/codeeditor/codeeditor.hpp index 678c9d227..736da6f63 100644 --- a/src/tools/codeeditor/codeeditor.hpp +++ b/src/tools/codeeditor/codeeditor.hpp @@ -194,6 +194,8 @@ class App : public UICodeEditorSplitter::Client { bool mDirTreeReady{ false }; std::unordered_set mTmpDocs; std::string mCurrentProject; + FontTrueType* mFont{ nullptr }; + FontTrueType* mFontMono{ nullptr }; void saveAllProcess(); @@ -310,7 +312,7 @@ class App : public UICodeEditorSplitter::Client { void toggleSettingsMenu(); FontTrueType* loadFont( const std::string& name, std::string fontPath, - const std::string& fallback ); + const std::string& fallback = "" ); void closeFolder(); @@ -318,6 +320,8 @@ class App : public UICodeEditorSplitter::Client { void updateGlobalSearchBarResults( const std::string& search, std::shared_ptr model ); + + void switchSidePanel(); }; #endif // EE_TOOLS_CODEEDITOR_HPP