mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Added support to move Tabs from one UITabWidget to another using the onDrop API.
This commit is contained in:
4
TODO.md
4
TODO.md
@@ -1,10 +1,6 @@
|
||||
|
||||
# TODO - Short and mid term plans.
|
||||
|
||||
## UITabWidget
|
||||
|
||||
* Add support to move Tabs from one `UITabWidget` to another using the onDrop API.
|
||||
|
||||
## UIIconTheme and UIIconThemeManager
|
||||
|
||||
Implement icon themes separated from the `UITheme` and customizable from a CSS file.
|
||||
|
||||
@@ -1564,6 +1564,16 @@ Enables/disables manually rearraging the tabs in the tab bar.
|
||||
|
||||
---
|
||||
|
||||
### tabbar-allow-drag-and-drop-tabs
|
||||
|
||||
Enables/disables the hability to move any tab from a TabWidget to another.
|
||||
|
||||
* Applicable to: EE::UI::UITabWidget (TabWidget)
|
||||
* Data Type: [boolean](#boolean-data-type)
|
||||
* Default value: `false`
|
||||
|
||||
---
|
||||
|
||||
### tab-closable
|
||||
|
||||
Enables/disables tabs to be closable with the middle mouse button click or by clicking on the close
|
||||
|
||||
@@ -52,6 +52,7 @@ class EE_API Event {
|
||||
MsgBoxConfirmClick,
|
||||
MsgBoxCancelClick,
|
||||
OnTabSelected,
|
||||
OnTabAdded,
|
||||
OnTabClosed,
|
||||
OnTabNavigate,
|
||||
OnClose, // Warning: Only some nodes will report this event.
|
||||
|
||||
@@ -371,7 +371,7 @@ class EE_API Node : public Transformable {
|
||||
|
||||
bool isChild( Node* child ) const;
|
||||
|
||||
bool inParentTreeOf( Node* Child ) const;
|
||||
bool inParentTreeOf( Node* child ) const;
|
||||
|
||||
void setLoadingState( bool loading );
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ enum class PropertyId : Uint32 {
|
||||
BorderBottomRightRadius = String::hash( "border-bottom-right-radius" ),
|
||||
TabBarHideOnSingleTab = String::hash( "tabbar-hide-on-single-tab" ),
|
||||
TabBarAllowRearrange = String::hash( "tabbar-allow-rearrange" ),
|
||||
TabBarAllowDragAndDrop = String::hash( "tabbar-allow-drag-and-drop-tabs" ),
|
||||
};
|
||||
|
||||
enum class PropertyType : Uint32 {
|
||||
|
||||
@@ -43,6 +43,8 @@ class EE_API UITab : public UISelectButton {
|
||||
String mText;
|
||||
std::string mOwnedName;
|
||||
UIWidget* mCloseButton;
|
||||
Float mDragTotalDiff;
|
||||
UITabWidget* mTabWidget;
|
||||
|
||||
Uint32 onDrag( const Vector2f& position, const Uint32& flags, const Sizef& dragDiff );
|
||||
|
||||
|
||||
@@ -141,6 +141,14 @@ class EE_API UITabWidget : public UIWidget {
|
||||
|
||||
void setAllowRearrangeTabs( bool allowRearrangeTabs );
|
||||
|
||||
bool getAllowDragAndDropTabs() const;
|
||||
|
||||
void setAllowDragAndDropTabs( bool allowDragAndDropTabs );
|
||||
|
||||
const Float& getTabVerticalDragResistance() const;
|
||||
|
||||
void setTabVerticalDragResistance( const Float& tabVerticalDragResistance );
|
||||
|
||||
protected:
|
||||
friend class UITab;
|
||||
|
||||
@@ -153,17 +161,25 @@ class EE_API UITabWidget : public UIWidget {
|
||||
TabTryCloseCallback mTabTryCloseCallback;
|
||||
bool mHideTabBarOnSingleTab;
|
||||
bool mAllowRearrangeTabs;
|
||||
bool mAllowDragAndDropTabs;
|
||||
Float mTabVerticalDragResistance;
|
||||
|
||||
void onThemeLoaded();
|
||||
|
||||
UITab* createTab( const String& text, UINode* nodeOwned, Drawable* icon );
|
||||
|
||||
void removeTab( const Uint32& index, bool destroyOwnedNode, bool destroyTab = true );
|
||||
|
||||
void removeTab( UITab* tab, bool destroyOwnedNode, bool destroyTab );
|
||||
|
||||
virtual void onSizeChange();
|
||||
|
||||
virtual void onChildCountChange( Node* child, const bool& removed );
|
||||
|
||||
virtual void onPaddingChange();
|
||||
|
||||
virtual Uint32 onMessage( const NodeMessage* msg );
|
||||
|
||||
void setContainerSize();
|
||||
|
||||
void posTabs();
|
||||
|
||||
@@ -773,16 +773,13 @@ bool Node::isChild( Node* child ) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Node::inParentTreeOf( Node* Child ) const {
|
||||
Node* ParentLoop = Child->mParentNode;
|
||||
|
||||
while ( NULL != ParentLoop ) {
|
||||
if ( ParentLoop == this )
|
||||
bool Node::inParentTreeOf( Node* child ) const {
|
||||
Node* node = child->mParentNode;
|
||||
while ( NULL != node ) {
|
||||
if ( node == this )
|
||||
return true;
|
||||
|
||||
ParentLoop = ParentLoop->mParentNode;
|
||||
node = node->mParentNode;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,4 +23,8 @@ const Uint32& NodeMessage::getFlags() const {
|
||||
NodeDropMessage::NodeDropMessage( Node* node, const Uint32& msg, Node* droppedNode ) :
|
||||
NodeMessage( node, msg ), mDroppedNode( droppedNode ) {}
|
||||
|
||||
Node* NodeDropMessage::getDroppedNode() const {
|
||||
return mDroppedNode;
|
||||
}
|
||||
|
||||
}} // namespace EE::Scene
|
||||
|
||||
@@ -362,6 +362,7 @@ void StyleSheetSpecification::registerDefaultProperties() {
|
||||
|
||||
registerProperty( "tabbar-hide-on-single-tab", "false" );
|
||||
registerProperty( "tabbar-allow-rearrange", "false" );
|
||||
registerProperty( "tabbar-allow-drag-and-drop-tabs", "false" );
|
||||
|
||||
// Shorthands
|
||||
registerShorthand( "margin", {"margin-top", "margin-right", "margin-bottom", "margin-left"},
|
||||
|
||||
@@ -442,11 +442,7 @@ Uint32 UINode::onCalculateDrag( const Vector2f& position, const Uint32& flags )
|
||||
|
||||
if ( onDrag( pos, flags, dragDiff ) ) {
|
||||
setPixelsPosition( mPosition - dragDiff );
|
||||
|
||||
mDragPoint = pos;
|
||||
|
||||
onPositionChange();
|
||||
|
||||
eventDispatcher->setNodeDragging( this );
|
||||
}
|
||||
}
|
||||
@@ -1137,9 +1133,9 @@ void UINode::setDragging( const bool& dragging ) {
|
||||
mEnabled = false;
|
||||
Node* found = getUISceneNode()->overFind( getEventDispatcher()->getMousePosf() );
|
||||
if ( found && found->isUINode() ) {
|
||||
found->asType<UINode>()->onDrop( this );
|
||||
NodeDropMessage msg( found, NodeMessage::Drop, this );
|
||||
found->messagePost( &msg );
|
||||
found->asType<UINode>()->onDrop( this );
|
||||
}
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ UITab* UITab::New() {
|
||||
return eeNew( UITab, () );
|
||||
}
|
||||
|
||||
UITab::UITab() : UISelectButton( "tab" ), mOwnedWidget( NULL ) {
|
||||
UITab::UITab() :
|
||||
UISelectButton( "tab" ), mOwnedWidget( NULL ), mDragTotalDiff( 0.f ), mTabWidget( NULL ) {
|
||||
mTextBox->setElementTag( mTag + "::text" );
|
||||
mIcon->setElementTag( mTag + "::icon" );
|
||||
auto cb = [&]( const Event* ) { onSizeChange(); };
|
||||
@@ -37,12 +38,13 @@ UITabWidget* UITab::getTabWidget() {
|
||||
if ( NULL != getParent() && NULL != getParent()->getParent() &&
|
||||
getParent()->getParent()->isType( UI_TYPE_TABWIDGET ) ) {
|
||||
return getParent()->getParent()->asType<UITabWidget>();
|
||||
} else if ( mTabWidget ) {
|
||||
return mTabWidget;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Uint32 UITab::onDrag( const Vector2f&, const Uint32&, const Sizef& dragDiff ) {
|
||||
Uint32 UITab::onDrag( const Vector2f& pos, const Uint32&, const Sizef& dragDiff ) {
|
||||
UITabWidget* tabW = getTabWidget();
|
||||
if ( !tabW )
|
||||
return 0;
|
||||
@@ -65,11 +67,27 @@ Uint32 UITab::onDrag( const Vector2f&, const Uint32&, const Sizef& dragDiff ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( tabW->getAllowDragAndDropTabs() && !( mFlags & UI_DRAG_VERTICAL ) ) {
|
||||
mDragTotalDiff += ( Float )( mDragPoint.y - pos.y );
|
||||
if ( eeabs( mDragTotalDiff ) >= tabW->getTabVerticalDragResistance() ) {
|
||||
setFlags( UI_DRAG_VERTICAL );
|
||||
setPixelsPosition( mPosition.x, mPosition.y - mDragTotalDiff );
|
||||
mDragPoint = pos;
|
||||
mTabWidget = getTabWidget();
|
||||
Vector2f posDiff( pos );
|
||||
worldToNode( posDiff );
|
||||
setParent( getUISceneNode()->getRoot() );
|
||||
setPixelsPosition( pos - posDiff );
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
Uint32 UITab::onDragStart( const Vector2i& position, const Uint32& flags ) {
|
||||
UITabWidget* tabW = getTabWidget();
|
||||
mTabWidget = NULL;
|
||||
mDragTotalDiff = 0;
|
||||
unsetFlags( UI_DRAG_VERTICAL );
|
||||
if ( tabW ) {
|
||||
for ( size_t i = 0; i < tabW->getTabCount(); i++ ) {
|
||||
UITab* tab = tabW->getTab( i );
|
||||
@@ -83,6 +101,10 @@ Uint32 UITab::onDragStart( const Vector2i& position, const Uint32& flags ) {
|
||||
|
||||
Uint32 UITab::onDragStop( const Vector2i& position, const Uint32& flags ) {
|
||||
UITabWidget* tabW = getTabWidget();
|
||||
if ( mTabWidget ) {
|
||||
setParent( tabW->getTabBar() );
|
||||
mTabWidget = NULL;
|
||||
}
|
||||
if ( tabW ) {
|
||||
for ( size_t i = 0; i < tabW->getTabCount(); i++ ) {
|
||||
UITab* tab = tabW->getTab( i );
|
||||
@@ -303,7 +325,7 @@ void UITab::updateTab() {
|
||||
} else {
|
||||
UIPushButton::setText( mText );
|
||||
}
|
||||
setDragEnabled( tTabW->getAllowRearrangeTabs() );
|
||||
setDragEnabled( tTabW->getAllowRearrangeTabs() || tTabW->getAllowDragAndDropTabs() );
|
||||
onAutoSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ UITabWidget::UITabWidget() :
|
||||
mTabSelected( NULL ),
|
||||
mTabSelectedIndex( eeINDEX_NOT_FOUND ),
|
||||
mHideTabBarOnSingleTab( false ),
|
||||
mAllowRearrangeTabs( false ) {
|
||||
mAllowRearrangeTabs( false ),
|
||||
mAllowDragAndDropTabs( false ),
|
||||
mTabVerticalDragResistance( PixelDensity::dpToPx( 64 ) ) {
|
||||
setHorizontalAlign( UI_HALIGN_CENTER );
|
||||
|
||||
mTabBar = UIWidget::NewWithTag( "tabwidget::tabbar" );
|
||||
@@ -218,6 +220,9 @@ bool UITabWidget::applyProperty( const StyleSheetProperty& attribute ) {
|
||||
case PropertyId::TabBarAllowRearrange:
|
||||
setAllowRearrangeTabs( attribute.asBool() );
|
||||
break;
|
||||
case PropertyId::TabBarAllowDragAndDrop:
|
||||
setAllowDragAndDropTabs( attribute.asBool() );
|
||||
break;
|
||||
default:
|
||||
return UIWidget::applyProperty( attribute );
|
||||
}
|
||||
@@ -424,6 +429,9 @@ UITabWidget* UITabWidget::add( UITab* tab ) {
|
||||
orderTabs();
|
||||
}
|
||||
|
||||
TabEvent tabEvent( this, tab, getTabIndex( tab ), Event::OnTabAdded );
|
||||
sendEvent( &tabEvent );
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -459,13 +467,19 @@ Uint32 UITabWidget::getTabCount() const {
|
||||
}
|
||||
|
||||
void UITabWidget::removeTab( const Uint32& index, bool destroyOwnedNode ) {
|
||||
removeTab( index, destroyOwnedNode, true );
|
||||
}
|
||||
|
||||
void UITabWidget::removeTab( const Uint32& index, bool destroyOwnedNode, bool destroyTab ) {
|
||||
eeASSERT( index < mTabs.size() );
|
||||
|
||||
UITab* tab = mTabs[index];
|
||||
|
||||
tab->close();
|
||||
tab->setVisible( false );
|
||||
tab->setEnabled( false );
|
||||
if ( destroyTab ) {
|
||||
tab->close();
|
||||
tab->setVisible( false );
|
||||
tab->setEnabled( false );
|
||||
}
|
||||
if ( destroyOwnedNode ) {
|
||||
tab->getOwnedWidget()->close();
|
||||
tab->getOwnedWidget()->setVisible( false );
|
||||
@@ -499,7 +513,11 @@ void UITabWidget::removeTab( const Uint32& index, bool destroyOwnedNode ) {
|
||||
}
|
||||
|
||||
void UITabWidget::removeTab( UITab* tab, bool destroyOwnedNode ) {
|
||||
removeTab( getTabIndex( tab ), destroyOwnedNode );
|
||||
removeTab( getTabIndex( tab ), destroyOwnedNode, true );
|
||||
}
|
||||
|
||||
void UITabWidget::removeTab( UITab* tab, bool destroyOwnedNode, bool destroyTab ) {
|
||||
removeTab( getTabIndex( tab ), destroyOwnedNode, destroyTab );
|
||||
}
|
||||
|
||||
void UITabWidget::removeAllTabs( bool destroyOwnedNode ) {
|
||||
@@ -628,6 +646,22 @@ void UITabWidget::setAllowRearrangeTabs( bool allowRearrangeTabs ) {
|
||||
}
|
||||
}
|
||||
|
||||
bool UITabWidget::getAllowDragAndDropTabs() const {
|
||||
return mAllowDragAndDropTabs;
|
||||
}
|
||||
|
||||
void UITabWidget::setAllowDragAndDropTabs( bool allowDragAndDropTabs ) {
|
||||
mAllowDragAndDropTabs = allowDragAndDropTabs;
|
||||
}
|
||||
|
||||
const Float& UITabWidget::getTabVerticalDragResistance() const {
|
||||
return mTabVerticalDragResistance;
|
||||
}
|
||||
|
||||
void UITabWidget::setTabVerticalDragResistance( const Float& tabVerticalDragResistance ) {
|
||||
mTabVerticalDragResistance = tabVerticalDragResistance;
|
||||
}
|
||||
|
||||
void UITabWidget::refreshOwnedWidget( UITab* tab ) {
|
||||
if ( NULL != tab && NULL != tab->getOwnedWidget() ) {
|
||||
tab->getOwnedWidget()->setParent( mNodeContainer );
|
||||
@@ -695,17 +729,24 @@ void UITabWidget::onSizeChange() {
|
||||
void UITabWidget::onChildCountChange( Node* child, const bool& removed ) {
|
||||
if ( !removed && child != mTabBar && child != mNodeContainer ) {
|
||||
if ( child->isType( UI_TYPE_TAB ) ) {
|
||||
UITab* Tab = static_cast<UITab*>( child );
|
||||
// This must be a tab that was dragging.
|
||||
if ( std::find( mTabs.begin(), mTabs.end(), child->asType<UITab>() ) != mTabs.end() )
|
||||
return;
|
||||
|
||||
Tab->setParent( mTabBar );
|
||||
UITab* tab = static_cast<UITab*>( child );
|
||||
|
||||
mTabs.push_back( Tab );
|
||||
tab->setParent( mTabBar );
|
||||
|
||||
mTabs.push_back( tab );
|
||||
|
||||
if ( NULL == mTabSelected ) {
|
||||
setTabSelected( Tab );
|
||||
setTabSelected( tab );
|
||||
} else {
|
||||
orderTabs();
|
||||
}
|
||||
|
||||
TabEvent tabEvent( this, tab, getTabIndex( tab ), Event::OnTabAdded );
|
||||
sendEvent( &tabEvent );
|
||||
} else {
|
||||
child->setParent( mNodeContainer );
|
||||
child->setVisible( false );
|
||||
@@ -722,6 +763,21 @@ void UITabWidget::onPaddingChange() {
|
||||
UIWidget::onPaddingChange();
|
||||
}
|
||||
|
||||
Uint32 UITabWidget::onMessage( const NodeMessage* msg ) {
|
||||
if ( msg->getMsg() == NodeMessage::Drop && mAllowDragAndDropTabs ) {
|
||||
const NodeDropMessage* dropMsg = static_cast<const NodeDropMessage*>( msg );
|
||||
if ( dropMsg->getDroppedNode()->isType( UI_TYPE_TAB ) ) {
|
||||
UITab* tab = dropMsg->getDroppedNode()->asType<UITab>();
|
||||
if ( tab->getTabWidget() != this ) {
|
||||
tab->getTabWidget()->removeTab( tab, false, false );
|
||||
add( tab );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UITabWidget::applyThemeToTabs() {
|
||||
if ( mStyleConfig.TabsEdgesDiffSkins ) {
|
||||
for ( Uint32 i = 0; i < mTabs.size(); i++ ) {
|
||||
|
||||
@@ -451,6 +451,7 @@ UITabWidget* App::createEditorWithTabWidget( Node* parent ) {
|
||||
tabWidget->setTabsClosable( true );
|
||||
tabWidget->setHideTabBarOnSingleTab( true );
|
||||
tabWidget->setAllowRearrangeTabs( true );
|
||||
tabWidget->setAllowDragAndDropTabs( true );
|
||||
tabWidget->addEventListener( Event::OnTabSelected, [&]( const Event* event ) {
|
||||
UITabWidget* tabWidget = event->getNode()->asType<UITabWidget>();
|
||||
mCurEditor = tabWidget->getTabSelected()->getOwnedWidget()->asType<UICodeEditor>();
|
||||
@@ -463,6 +464,16 @@ UITabWidget* App::createEditorWithTabWidget( Node* parent ) {
|
||||
tabWidget->addEventListener( Event::OnTabClosed, [&]( const Event* event ) {
|
||||
onTabClosed( static_cast<const TabEvent*>( event ) );
|
||||
} );
|
||||
tabWidget->addEventListener( Event::OnTabAdded, [&]( const Event* event ) {
|
||||
UITabWidget* tabWidget = event->getNode()->asType<UITabWidget>();
|
||||
if ( tabWidget->getTabCount() == 2 && tabWidget->getTab( 0 )
|
||||
->getOwnedWidget()
|
||||
->asType<UICodeEditor>()
|
||||
->getDocument()
|
||||
.isEmpty() ) {
|
||||
tabWidget->removeTab( (Uint32)0 );
|
||||
}
|
||||
} );
|
||||
createCodeEditorInTabWidget( tabWidget );
|
||||
mTabWidgets.push_back( tabWidget );
|
||||
return tabWidget;
|
||||
@@ -508,13 +519,6 @@ void App::openFileDialog() {
|
||||
UITab* addedTab = d.first;
|
||||
loadFileFromPath( event->getNode()->asType<UIFileDialog>()->getFullPath(), d.second );
|
||||
tabWidget->setTabSelected( addedTab );
|
||||
UITab* firstTab = tabWidget->getTab( 0 );
|
||||
if ( addedTab != firstTab ) {
|
||||
UICodeEditor* editor = (UICodeEditor*)firstTab->getOwnedWidget();
|
||||
if ( editor->getDocument().isEmpty() ) {
|
||||
tabWidget->removeTab( firstTab );
|
||||
}
|
||||
}
|
||||
} );
|
||||
dialog->addEventListener( Event::OnWindowClose, [&]( const Event* ) {
|
||||
if ( mCurEditor && !SceneManager::instance()->isShootingDown() )
|
||||
|
||||
Reference in New Issue
Block a user