mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Allow to split editors views by dragging tabs into the tab widget corners.
This commit is contained in:
@@ -574,7 +574,7 @@ class EE_API Node : public Transformable {
|
||||
|
||||
void childRemove( Node* node );
|
||||
|
||||
Rectf getScreenBounds();
|
||||
Rectf getScreenBounds() const;
|
||||
|
||||
void setInternalPosition( const Vector2f& Pos );
|
||||
|
||||
|
||||
10
include/eepp/ui/splitdirection.hpp
Normal file
10
include/eepp/ui/splitdirection.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef EE_UI_SPLIT_DIRECTION_HPP
|
||||
#define EE_UI_SPLIT_DIRECTION_HPP
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
enum class SplitDirection { Left, Right, Top, Bottom };
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
#endif // EE_UI_SPLIT_DIRECTION_HPP
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef EE_UI_TOOLS_UICODEEDITORSPLITTER_HPP
|
||||
#define EE_UI_TOOLS_UICODEEDITORSPLITTER_HPP
|
||||
|
||||
#include <eepp/ui/splitdirection.hpp>
|
||||
#include <eepp/ui/uicodeeditor.hpp>
|
||||
#include <eepp/ui/uimessagebox.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
@@ -19,8 +20,6 @@ class EE_API UICodeEditorSplitter {
|
||||
|
||||
static const std::map<KeyBindings::Shortcut, std::string> getLocalDefaultKeybindings();
|
||||
|
||||
enum class SplitDirection { Left, Right, Top, Bottom };
|
||||
|
||||
class EE_API Client {
|
||||
public:
|
||||
virtual ~Client() {};
|
||||
@@ -355,6 +354,12 @@ class EE_API UICodeEditorSplitter {
|
||||
|
||||
void setOnTabWidgetCreateCb( std::function<void( UITabWidget* )> cb );
|
||||
|
||||
bool getVisualSplitting() const;
|
||||
void setVisualSplitting( bool visualSplitting );
|
||||
|
||||
Float getVisualSplitEdgePercent() const;
|
||||
void setVisualSplitEdgePercent( Float visualSplitEdgePercent );
|
||||
|
||||
protected:
|
||||
UISceneNode* mUISceneNode{ nullptr };
|
||||
std::shared_ptr<ThreadPool> mThreadPool;
|
||||
@@ -367,6 +372,7 @@ class EE_API UICodeEditorSplitter {
|
||||
Client* mClient;
|
||||
bool mHideTabBarOnSingleTab{ true };
|
||||
bool mFirstCodeEditor{ true };
|
||||
bool mVisualSplitting{ true };
|
||||
UICodeEditor* mAboutToAddEditor{ nullptr };
|
||||
UIMessageBox* mTryCloseMsgBox{ nullptr };
|
||||
Mutex mTabWidgetMutex;
|
||||
@@ -378,6 +384,7 @@ class EE_API UICodeEditorSplitter {
|
||||
std::vector<NavigationRecord> mNavigationHistory;
|
||||
size_t mNavigationHistoryPos{ std::numeric_limits<size_t>::max() };
|
||||
std::function<void( UITabWidget* )> mOnTabWidgetCreateCb;
|
||||
Float mVisualSplitEdgePercent{ 0.1 };
|
||||
|
||||
UICodeEditorSplitter( UICodeEditorSplitter::Client* client, UISceneNode* sceneNode,
|
||||
std::shared_ptr<ThreadPool> threadPool,
|
||||
@@ -387,6 +394,12 @@ class EE_API UICodeEditorSplitter {
|
||||
virtual void onTabClosed( const TabEvent* tabEvent );
|
||||
|
||||
void closeAllTabs( std::vector<UITab*> tabs, UITabWidget::FocusTabBehavior focusTabBehavior );
|
||||
|
||||
UITabWidget* createTabWidget( Node* parent );
|
||||
|
||||
UITabWidget* splitTabWidget( SplitDirection, UITabWidget* );
|
||||
|
||||
void updateTabWidgetVisualSplitting();
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::Tools
|
||||
|
||||
@@ -428,6 +428,8 @@ class EE_API UINode : public Node {
|
||||
void smartClipStart( const ClipType& reqClipType );
|
||||
|
||||
void smartClipEnd( const ClipType& reqClipType );
|
||||
|
||||
Color getDroppableHoveringColor();
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#define EE_UI_UITABWIDGET_HPP
|
||||
|
||||
#include <deque>
|
||||
#include <eepp/ui/splitdirection.hpp>
|
||||
#include <eepp/ui/uitab.hpp>
|
||||
#include <eepp/ui/uiwidget.hpp>
|
||||
#include <optional>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
@@ -26,6 +28,8 @@ class EE_API TabEvent : public Event {
|
||||
|
||||
class EE_API UITabWidget : public UIWidget {
|
||||
public:
|
||||
using SplitFunctionCb = std::function<UITabWidget*( SplitDirection, UITabWidget* )>;
|
||||
|
||||
enum class FocusTabBehavior { Closest, FocusOrder, Default };
|
||||
|
||||
class StyleConfig {
|
||||
@@ -157,7 +161,7 @@ class EE_API UITabWidget : public UIWidget {
|
||||
|
||||
void setAllowRearrangeTabs( bool allowRearrangeTabs );
|
||||
|
||||
bool getAllowDragAndDropTabs() const;
|
||||
bool allowDragAndDropTabs() const;
|
||||
|
||||
void setAllowDragAndDropTabs( bool allowDragAndDropTabs );
|
||||
|
||||
@@ -187,6 +191,8 @@ class EE_API UITabWidget : public UIWidget {
|
||||
|
||||
void swapTabs( UITab* left, UITab* right );
|
||||
|
||||
void setSplitFunction( SplitFunctionCb cb, Float splitEdgePercent = 0.1 );
|
||||
|
||||
protected:
|
||||
friend class UITab;
|
||||
|
||||
@@ -209,6 +215,8 @@ class EE_API UITabWidget : public UIWidget {
|
||||
FocusTabBehavior mFocusTabBehavior{ FocusTabBehavior::Closest };
|
||||
std::deque<UITab*> mFocusHistory;
|
||||
UIPopUpMenu* mCurrentMenu{ nullptr };
|
||||
SplitFunctionCb mSplitFn;
|
||||
Float mSplitEdgePercent{ 0.1 };
|
||||
|
||||
void onThemeLoaded();
|
||||
|
||||
@@ -229,6 +237,8 @@ class EE_API UITabWidget : public UIWidget {
|
||||
|
||||
virtual Uint32 onMessage( const NodeMessage* msg );
|
||||
|
||||
virtual void drawDroppableHovering();
|
||||
|
||||
void setContainerSize();
|
||||
|
||||
void posTabs();
|
||||
@@ -254,6 +264,8 @@ class EE_API UITabWidget : public UIWidget {
|
||||
void insertFocusHistory( UITab* tab );
|
||||
|
||||
void eraseFocusHistory( UITab* tab );
|
||||
|
||||
std::optional<SplitDirection> getDropDirection() const;
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -360,6 +360,7 @@
|
||||
../../include/eepp/ui/models/persistentmodelindex.hpp
|
||||
../../include/eepp/ui/models/sortingproxymodel.hpp
|
||||
../../include/eepp/ui/models/widgettreemodel.hpp
|
||||
../../include/eepp/ui/splitdirection.hpp
|
||||
../../include/eepp/ui/tools/textureatlaseditor.hpp
|
||||
../../include/eepp/ui/tools/uicodeeditorsplitter.hpp
|
||||
../../include/eepp/ui/tools/uicolorpicker.hpp
|
||||
|
||||
@@ -510,7 +510,7 @@ void Node::onSizeChange() {
|
||||
invalidateDraw();
|
||||
}
|
||||
|
||||
Rectf Node::getScreenBounds() {
|
||||
Rectf Node::getScreenBounds() const {
|
||||
return Rectf( Vector2f( mScreenPosi.x, mScreenPosi.y ),
|
||||
Sizef( (Float)(int)mSize.getWidth(), (Float)(int)mSize.getHeight() ) );
|
||||
}
|
||||
|
||||
@@ -626,11 +626,7 @@ void UICodeEditorSplitter::removeUnusedTab( UITabWidget* tabWidget, bool destroy
|
||||
}
|
||||
}
|
||||
|
||||
UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool openCurEditor ) {
|
||||
eeASSERT( curWidgetExists() );
|
||||
if ( nullptr == mBaseLayout )
|
||||
mBaseLayout = parent;
|
||||
UICodeEditor* prevCurEditor = mCurEditor;
|
||||
UITabWidget* UICodeEditorSplitter::createTabWidget( Node* parent ) {
|
||||
UITabWidget* tabWidget = UITabWidget::New();
|
||||
tabWidget->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
|
||||
tabWidget->setParent( parent );
|
||||
@@ -641,6 +637,13 @@ UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool
|
||||
tabWidget->setAllowSwitchTabsInEmptySpaces( true );
|
||||
tabWidget->setEnabledCreateContextMenu( true );
|
||||
tabWidget->setFocusTabBehavior( UITabWidget::FocusTabBehavior::FocusOrder );
|
||||
if ( mVisualSplitting ) {
|
||||
tabWidget->setSplitFunction(
|
||||
[this]( SplitDirection dir, UITabWidget* widget ) -> UITabWidget* {
|
||||
return splitTabWidget( dir, widget );
|
||||
},
|
||||
mVisualSplitEdgePercent );
|
||||
}
|
||||
tabWidget->addEventListener( Event::OnTabSelected, [this]( const Event* event ) {
|
||||
UITabWidget* tabWidget = event->getNode()->asType<UITabWidget>();
|
||||
if ( tabWidget->getTabSelected()->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) {
|
||||
@@ -663,6 +666,17 @@ UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool
|
||||
} );
|
||||
if ( mOnTabWidgetCreateCb )
|
||||
mOnTabWidgetCreateCb( tabWidget );
|
||||
Lock l( mTabWidgetMutex );
|
||||
mTabWidgets.push_back( tabWidget );
|
||||
return tabWidget;
|
||||
}
|
||||
|
||||
UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool openCurEditor ) {
|
||||
eeASSERT( curWidgetExists() );
|
||||
if ( nullptr == mBaseLayout )
|
||||
mBaseLayout = parent;
|
||||
UICodeEditor* prevCurEditor = mCurEditor;
|
||||
UITabWidget* tabWidget = createTabWidget( parent );
|
||||
auto editorData = createCodeEditorInTabWidget( tabWidget );
|
||||
if ( editorData.first == nullptr || editorData.second == nullptr ) {
|
||||
if ( !mTabWidgets.empty() && mTabWidgets[0]->getTabCount() > 0 ) {
|
||||
@@ -684,8 +698,6 @@ UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool
|
||||
editorData.first->setTooltipText( path );
|
||||
}
|
||||
mAboutToAddEditor = nullptr;
|
||||
Lock l( mTabWidgetMutex );
|
||||
mTabWidgets.push_back( tabWidget );
|
||||
return tabWidget;
|
||||
}
|
||||
|
||||
@@ -1205,6 +1217,51 @@ UISplitter* UICodeEditorSplitter::split( const SplitDirection& direction, UIWidg
|
||||
return splitter;
|
||||
}
|
||||
|
||||
UITabWidget* UICodeEditorSplitter::splitTabWidget( SplitDirection direction,
|
||||
UITabWidget* tabWidget ) {
|
||||
if ( !tabWidget )
|
||||
return nullptr;
|
||||
UIOrientation orientation =
|
||||
direction == SplitDirection::Left || direction == SplitDirection::Right
|
||||
? UIOrientation::Horizontal
|
||||
: UIOrientation::Vertical;
|
||||
Node* parent = tabWidget->getParent();
|
||||
UISplitter* parentSplitter = nullptr;
|
||||
bool wasFirst = true;
|
||||
|
||||
if ( parent->isType( UI_TYPE_SPLITTER ) ) {
|
||||
parentSplitter = parent->asType<UISplitter>();
|
||||
wasFirst = parentSplitter->getFirstWidget() == tabWidget;
|
||||
if ( !parentSplitter->isFull() ) {
|
||||
parentSplitter->setOrientation( orientation );
|
||||
UITabWidget* newTabWidget = createTabWidget( parentSplitter );
|
||||
if ( direction == SplitDirection::Left || direction == SplitDirection::Top )
|
||||
parentSplitter->swap();
|
||||
return newTabWidget;
|
||||
}
|
||||
}
|
||||
|
||||
UISplitter* splitter = UISplitter::New();
|
||||
splitter->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
|
||||
splitter->setOrientation( orientation );
|
||||
tabWidget->detach();
|
||||
splitter->setParent( parent );
|
||||
tabWidget->setParent( splitter );
|
||||
UITabWidget* newTabWidget = createTabWidget( splitter );
|
||||
if ( direction == SplitDirection::Left || direction == SplitDirection::Top )
|
||||
splitter->swap();
|
||||
|
||||
if ( parentSplitter ) {
|
||||
if ( wasFirst && parentSplitter->getFirstWidget() != splitter ) {
|
||||
parentSplitter->swap();
|
||||
} else if ( !wasFirst && parentSplitter->getLastWidget() != splitter ) {
|
||||
parentSplitter->swap();
|
||||
}
|
||||
}
|
||||
|
||||
return newTabWidget;
|
||||
}
|
||||
|
||||
void UICodeEditorSplitter::switchToTab( Int32 index ) {
|
||||
UITabWidget* tabWidget = tabWidgetFromWidget( mCurWidget );
|
||||
if ( tabWidget ) {
|
||||
@@ -1665,4 +1722,40 @@ void UICodeEditorSplitter::setOnTabWidgetCreateCb( std::function<void( UITabWidg
|
||||
mOnTabWidgetCreateCb = std::move( cb );
|
||||
}
|
||||
|
||||
bool UICodeEditorSplitter::getVisualSplitting() const {
|
||||
return mVisualSplitting;
|
||||
}
|
||||
|
||||
void UICodeEditorSplitter::setVisualSplitting( bool visualSplitting ) {
|
||||
if ( mVisualSplitting != visualSplitting ) {
|
||||
mVisualSplitting = visualSplitting;
|
||||
updateTabWidgetVisualSplitting();
|
||||
}
|
||||
}
|
||||
|
||||
Float UICodeEditorSplitter::getVisualSplitEdgePercent() const {
|
||||
return mVisualSplitEdgePercent;
|
||||
}
|
||||
|
||||
void UICodeEditorSplitter::setVisualSplitEdgePercent( Float visualSplitEdgePercent ) {
|
||||
if ( mVisualSplitEdgePercent != visualSplitEdgePercent ) {
|
||||
mVisualSplitEdgePercent = visualSplitEdgePercent;
|
||||
updateTabWidgetVisualSplitting();
|
||||
}
|
||||
}
|
||||
|
||||
void UICodeEditorSplitter::updateTabWidgetVisualSplitting() {
|
||||
for ( UITabWidget* tabWidget : mTabWidgets ) {
|
||||
if ( mVisualSplitting ) {
|
||||
tabWidget->setSplitFunction(
|
||||
[this]( SplitDirection dir, UITabWidget* widget ) -> UITabWidget* {
|
||||
return splitTabWidget( dir, widget );
|
||||
},
|
||||
mVisualSplitEdgePercent );
|
||||
} else {
|
||||
tabWidget->setSplitFunction( nullptr, mVisualSplitEdgePercent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace EE::UI::Tools
|
||||
|
||||
@@ -567,25 +567,10 @@ void UINode::drawOverNode() {
|
||||
}
|
||||
|
||||
void UINode::drawDroppableHovering() {
|
||||
const PropertyDefinition* def =
|
||||
StyleSheetSpecification::instance()->getProperty( "droppable-hovering-color" );
|
||||
Color color = Color::fromString( def->getDefaultValue() );
|
||||
if ( isWidget() ) {
|
||||
UIWidget* widget = asType<UIWidget>();
|
||||
std::string colorString = widget->getPropertyString( def );
|
||||
if ( !colorString.empty() ) {
|
||||
color = Color::fromString( colorString );
|
||||
} else {
|
||||
colorString = mUISceneNode->getRoot()->getPropertyString( def );
|
||||
if ( !colorString.empty() )
|
||||
color = Color::fromString( colorString );
|
||||
}
|
||||
}
|
||||
|
||||
Primitives P;
|
||||
P.setFillMode( DRAW_FILL );
|
||||
P.setBlendMode( getBlendMode() );
|
||||
P.setColor( color );
|
||||
P.setColor( getDroppableHoveringColor() );
|
||||
P.setLineWidth( PixelDensity::dpToPxI( 1 ) );
|
||||
P.drawRectangle( getScreenBounds() );
|
||||
}
|
||||
@@ -1053,6 +1038,24 @@ void UINode::smartClipEnd( const ClipType& reqClipType ) {
|
||||
smartClipEnd( reqClipType, isMeOrParentTreeScaledOrRotatedOrFrameBuffer() );
|
||||
}
|
||||
|
||||
Color UINode::getDroppableHoveringColor() {
|
||||
const PropertyDefinition* def =
|
||||
StyleSheetSpecification::instance()->getProperty( "droppable-hovering-color" );
|
||||
Color color = Color::fromString( def->getDefaultValue() );
|
||||
if ( isWidget() ) {
|
||||
UIWidget* widget = asType<UIWidget>();
|
||||
std::string colorString = widget->getPropertyString( def );
|
||||
if ( !colorString.empty() ) {
|
||||
color = Color::fromString( colorString );
|
||||
} else {
|
||||
colorString = mUISceneNode->getRoot()->getPropertyString( def );
|
||||
if ( !colorString.empty() )
|
||||
color = Color::fromString( colorString );
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
void UINode::nodeDraw() {
|
||||
if ( mVisible ) {
|
||||
if ( mNodeFlags & NODE_FLAG_POSITION_DIRTY )
|
||||
|
||||
@@ -76,7 +76,7 @@ Uint32 UITab::onDrag( const Vector2f& pos, const Uint32&, const Sizef& dragDiff
|
||||
tabW->swapTabs( tab, this );
|
||||
}
|
||||
|
||||
if ( tabW->getAllowDragAndDropTabs() && !( mFlags & UI_DRAG_VERTICAL ) ) {
|
||||
if ( tabW->allowDragAndDropTabs() && !( mFlags & UI_DRAG_VERTICAL ) ) {
|
||||
mDragTotalDiff += mDragPoint.y - pos.y;
|
||||
if ( eeabs( mDragTotalDiff ) >= tabW->getTabVerticalDragResistance() ) {
|
||||
setFlags( UI_DRAG_VERTICAL );
|
||||
@@ -90,7 +90,7 @@ Uint32 UITab::onDrag( const Vector2f& pos, const Uint32&, const Sizef& dragDiff
|
||||
}
|
||||
}
|
||||
|
||||
if ( tabW->getAllowDragAndDropTabs() ) {
|
||||
if ( tabW->allowDragAndDropTabs() ) {
|
||||
setEnabled( false );
|
||||
Node* overFind = getUISceneNode()->overFind( pos );
|
||||
setEnabled( true );
|
||||
@@ -435,7 +435,7 @@ void UITab::updateTab() {
|
||||
} else {
|
||||
UIPushButton::setText( mText );
|
||||
}
|
||||
setDragEnabled( tTabW->getAllowRearrangeTabs() || tTabW->getAllowDragAndDropTabs() );
|
||||
setDragEnabled( tTabW->getAllowRearrangeTabs() || tTabW->allowDragAndDropTabs() );
|
||||
onAutoSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ std::string UITabWidget::getPropertyString( const PropertyDefinition* propertyDe
|
||||
case PropertyId::TabBarAllowRearrange:
|
||||
return getAllowRearrangeTabs() ? "true" : "false";
|
||||
case PropertyId::TabBarAllowDragAndDrop:
|
||||
return getAllowDragAndDropTabs() ? "true" : "false";
|
||||
return allowDragAndDropTabs() ? "true" : "false";
|
||||
case PropertyId::TabAllowSwitchTabsInEmptySpaces:
|
||||
return getAllowSwitchTabsInEmptySpaces() ? "true" : "false";
|
||||
case PropertyId::TabCloseButtonVisible:
|
||||
@@ -833,7 +833,7 @@ void UITabWidget::setAllowRearrangeTabs( bool allowRearrangeTabs ) {
|
||||
}
|
||||
}
|
||||
|
||||
bool UITabWidget::getAllowDragAndDropTabs() const {
|
||||
bool UITabWidget::allowDragAndDropTabs() const {
|
||||
return mAllowDragAndDropTabs;
|
||||
}
|
||||
|
||||
@@ -859,7 +859,8 @@ void UITabWidget::setAllowSwitchTabsInEmptySpaces( bool allowSwitchTabsInEmptySp
|
||||
|
||||
bool UITabWidget::acceptsDropOfWidget( const UIWidget* widget ) {
|
||||
return mAllowDragAndDropTabs && widget && UI_TYPE_TAB == widget->getType() &&
|
||||
!isParentOf( widget ) && widget->asConstType<UITab>()->getTabWidget() != this;
|
||||
!isParentOf( widget ) &&
|
||||
( mSplitFn || widget->asConstType<UITab>()->getTabWidget() != this );
|
||||
}
|
||||
|
||||
const Color& UITabWidget::getDroppableHoveringColor() const {
|
||||
@@ -933,6 +934,11 @@ void UITabWidget::swapTabs( UITab* left, UITab* right ) {
|
||||
}
|
||||
}
|
||||
|
||||
void UITabWidget::setSplitFunction( SplitFunctionCb cb, Float splitEdgePercent ) {
|
||||
mSplitFn = std::move( cb );
|
||||
mSplitEdgePercent = splitEdgePercent;
|
||||
}
|
||||
|
||||
void UITabWidget::selectPreviousTab() {
|
||||
if ( eeINDEX_NOT_FOUND != mTabSelectedIndex && mTabSelectedIndex > 0 ) {
|
||||
setTabSelected( getTab( mTabSelectedIndex - 1 ) );
|
||||
@@ -1009,10 +1015,19 @@ Uint32 UITabWidget::onMessage( const NodeMessage* msg ) {
|
||||
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()->getAllowDragAndDropTabs() ) {
|
||||
auto dir = getDropDirection();
|
||||
if ( !mSplitFn || !dir ) {
|
||||
if ( tab->getTabWidget() != this && tab->getTabWidget()->allowDragAndDropTabs() ) {
|
||||
tab->getTabWidget()->removeTab( tab, false, false, false );
|
||||
add( tab );
|
||||
setTabSelected( tab );
|
||||
return 1;
|
||||
}
|
||||
} else if ( dir && tab->getTabWidget()->allowDragAndDropTabs() ) {
|
||||
tab->getTabWidget()->removeTab( tab, false, false, false );
|
||||
add( tab );
|
||||
setTabSelected( tab );
|
||||
auto tabWidget = mSplitFn( *dir, this );
|
||||
tabWidget->add( tab );
|
||||
tabWidget->setTabSelected( tab );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1030,6 +1045,65 @@ Uint32 UITabWidget::onMessage( const NodeMessage* msg ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::optional<SplitDirection> UITabWidget::getDropDirection() const {
|
||||
Vector2f mousePos( getEventDispatcher()->getMousePosf() );
|
||||
mousePos = convertToNodeSpace( mousePos );
|
||||
|
||||
if ( mTabBar->isVisible() && mousePos.y <= mTabBar->getPixelsSize().y )
|
||||
return {};
|
||||
|
||||
if ( mousePos.y <= mSize.y * mSplitEdgePercent ) {
|
||||
return SplitDirection::Top;
|
||||
} else if ( mousePos.y >= mSize.y - mSize.y * mSplitEdgePercent ) {
|
||||
return SplitDirection::Bottom;
|
||||
} else if ( mousePos.x <= mSize.x * mSplitEdgePercent ) {
|
||||
return SplitDirection::Left;
|
||||
} else if ( mousePos.x >= mSize.x - mSize.x * mSplitEdgePercent ) {
|
||||
return SplitDirection::Right;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void UITabWidget::drawDroppableHovering() {
|
||||
if ( mSplitFn ) {
|
||||
auto dir = getDropDirection();
|
||||
auto rect( getScreenBounds() );
|
||||
if ( mTabBar->isVisible() )
|
||||
rect.Top += mTabBar->getPixelsSize().getHeight();
|
||||
|
||||
if ( dir ) {
|
||||
constexpr auto splitSize = 0.5f;
|
||||
switch ( *dir ) {
|
||||
case SplitDirection::Top:
|
||||
rect.Bottom = rect.Top + mSize.y * splitSize;
|
||||
break;
|
||||
case SplitDirection::Bottom:
|
||||
rect.Top = rect.Bottom - mSize.y * splitSize;
|
||||
break;
|
||||
case SplitDirection::Left:
|
||||
rect.Right = rect.Left + mSize.x * splitSize;
|
||||
break;
|
||||
case SplitDirection::Right:
|
||||
rect.Left = rect.Right - mSize.x * splitSize;
|
||||
break;
|
||||
}
|
||||
} else if ( std::any_of( mTabs.begin(), mTabs.end(),
|
||||
[]( const UITab* tab ) { return tab->isDragging(); } ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Primitives P;
|
||||
P.setFillMode( DRAW_FILL );
|
||||
P.setBlendMode( getBlendMode() );
|
||||
P.setColor( UINode::getDroppableHoveringColor() );
|
||||
P.setLineWidth( PixelDensity::dpToPxI( 1 ) );
|
||||
P.drawRectangle( rect );
|
||||
} else {
|
||||
UIWidget::drawDroppableHovering();
|
||||
}
|
||||
}
|
||||
|
||||
void UITabWidget::applyThemeToTabs() {
|
||||
if ( mStyleConfig.TabsEdgesDiffSkins ) {
|
||||
for ( Uint32 i = 0; i < mTabs.size(); i++ ) {
|
||||
|
||||
@@ -651,8 +651,7 @@ void AppConfig::loadDocuments( UICodeEditorSplitter* editorSplitter, json j,
|
||||
}
|
||||
} else if ( j["type"] == "splitter" ) {
|
||||
UISplitter* splitter = editorSplitter->split(
|
||||
j["orientation"] == "horizontal" ? UICodeEditorSplitter::SplitDirection::Right
|
||||
: UICodeEditorSplitter::SplitDirection::Bottom,
|
||||
j["orientation"] == "horizontal" ? SplitDirection::Right : SplitDirection::Bottom,
|
||||
curTabWidget->getTabSelected()->getOwnedWidget()->asType<UICodeEditor>(), false );
|
||||
|
||||
if ( nullptr == splitter )
|
||||
|
||||
@@ -201,26 +201,22 @@ class App : public UICodeEditorSplitter::Client {
|
||||
[this] { mTerminalManager->createTerminalInSplitter(); } );
|
||||
t.setCommand( "terminal-split-right", [this] {
|
||||
auto cwd = getCurrentWorkingDir();
|
||||
mSplitter->split( UICodeEditorSplitter::SplitDirection::Right,
|
||||
mSplitter->getCurWidget(), false );
|
||||
mSplitter->split( SplitDirection::Right, mSplitter->getCurWidget(), false );
|
||||
mTerminalManager->createNewTerminal( "", nullptr, cwd );
|
||||
} );
|
||||
t.setCommand( "terminal-split-bottom", [this] {
|
||||
auto cwd = getCurrentWorkingDir();
|
||||
mSplitter->split( UICodeEditorSplitter::SplitDirection::Bottom,
|
||||
mSplitter->getCurWidget(), false );
|
||||
mSplitter->split( SplitDirection::Bottom, mSplitter->getCurWidget(), false );
|
||||
mTerminalManager->createNewTerminal( "", nullptr, cwd );
|
||||
} );
|
||||
t.setCommand( "terminal-split-left", [this] {
|
||||
auto cwd = getCurrentWorkingDir();
|
||||
mSplitter->split( UICodeEditorSplitter::SplitDirection::Left, mSplitter->getCurWidget(),
|
||||
false );
|
||||
mSplitter->split( SplitDirection::Left, mSplitter->getCurWidget(), false );
|
||||
mTerminalManager->createNewTerminal( "", nullptr, cwd );
|
||||
} );
|
||||
t.setCommand( "terminal-split-top", [this] {
|
||||
auto cwd = getCurrentWorkingDir();
|
||||
mSplitter->split( UICodeEditorSplitter::SplitDirection::Top, mSplitter->getCurWidget(),
|
||||
false );
|
||||
mSplitter->split( SplitDirection::Top, mSplitter->getCurWidget(), false );
|
||||
mTerminalManager->createNewTerminal( "", nullptr, cwd );
|
||||
} );
|
||||
t.setCommand( "reopen-closed-tab", [this] { reopenClosedTab(); } );
|
||||
|
||||
@@ -42,15 +42,13 @@ UITerminal* TerminalManager::createTerminalInSplitter( const std::string& workin
|
||||
switch ( config.term.newTerminalOrientation ) {
|
||||
case NewTerminalOrientation::Vertical: {
|
||||
auto cwd = workingDir.empty() ? mApp->getCurrentWorkingDir() : workingDir;
|
||||
splitter->split( UICodeEditorSplitter::SplitDirection::Right,
|
||||
splitter->getCurWidget(), false );
|
||||
splitter->split( SplitDirection::Right, splitter->getCurWidget(), false );
|
||||
term = createNewTerminal( "", nullptr, cwd, "", {}, fallback );
|
||||
break;
|
||||
}
|
||||
case NewTerminalOrientation::Horizontal: {
|
||||
auto cwd = workingDir.empty() ? mApp->getCurrentWorkingDir() : workingDir;
|
||||
splitter->split( UICodeEditorSplitter::SplitDirection::Bottom,
|
||||
splitter->getCurWidget(), false );
|
||||
splitter->split( SplitDirection::Bottom, splitter->getCurWidget(), false );
|
||||
term = createNewTerminal( "", nullptr, cwd, "", {}, fallback );
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user