2022-09-05 17:29:42 +08:00
/*******************************************************************************
* * Qt Advanced Docking System
* * Copyright ( C ) 2017 Uwe Kindler
* *
* * This library is free software ; you can redistribute it and / or
* * modify it under the terms of the GNU Lesser General Public
* * License as published by the Free Software Foundation ; either
* * version 2.1 of the License , or ( at your option ) any later version .
* *
* * This library is distributed in the hope that it will be useful ,
* * but WITHOUT ANY WARRANTY ; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* * Lesser General Public License for more details .
* *
* * You should have received a copy of the GNU Lesser General Public
* * License along with this library ; If not , see < http : //www.gnu.org/licenses/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//============================================================================
2022-11-01 20:41:36 +08:00
/// \file AutoHideTab.cpp
2022-09-05 17:29:42 +08:00
/// \author Syarif Fakhri
/// \date 05.09.2022
2022-11-01 20:41:36 +08:00
/// \brief Implementation of CAutoHideTab class
2022-09-05 17:29:42 +08:00
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
2022-11-01 20:41:36 +08:00
# include "AutoHideTab.h"
2022-09-05 17:29:42 +08:00
# include <QBoxLayout>
2022-11-04 15:51:17 +08:00
# include <QApplication>
2022-11-07 17:15:14 +08:00
# include <QElapsedTimer>
2023-07-07 17:21:54 +08:00
# include <QMenu>
2022-09-05 17:29:42 +08:00
2022-11-01 20:41:36 +08:00
# include "AutoHideDockContainer.h"
# include "AutoHideSideBar.h"
2022-09-08 11:30:56 +08:00
# include "DockAreaWidget.h"
2022-09-12 15:55:45 +08:00
# include "DockManager.h"
2022-09-05 17:29:42 +08:00
# include "DockWidget.h"
2023-07-07 20:42:13 +08:00
# include "FloatingDragPreview.h"
# include "DockOverlay.h"
2022-09-05 17:29:42 +08:00
namespace ads
{
2023-07-07 19:35:55 +08:00
static const char * const LocationProperty = " Location " ;
2022-09-05 17:29:42 +08:00
/**
* Private data class of CDockWidgetTab class ( pimpl )
*/
2022-11-01 19:06:59 +08:00
struct AutoHideTabPrivate
2022-09-05 17:29:42 +08:00
{
2022-11-01 19:06:59 +08:00
CAutoHideTab * _this ;
2022-10-28 22:28:23 +08:00
CDockWidget * DockWidget = nullptr ;
2022-11-01 19:06:59 +08:00
CAutoHideSideBar * SideBar = nullptr ;
2022-09-13 10:42:58 +08:00
Qt : : Orientation Orientation { Qt : : Vertical } ;
2022-11-07 17:15:14 +08:00
QElapsedTimer TimeSinceHoverMousePress ;
2023-07-07 20:42:13 +08:00
bool MousePressed = false ;
eDragState DragState = DraggingInactive ;
QPoint GlobalDragStartMousePosition ;
QPoint DragStartMousePosition ;
IFloatingWidget * FloatingWidget = nullptr ;
2022-09-05 17:29:42 +08:00
/**
* Private data constructor
*/
2022-11-01 19:06:59 +08:00
AutoHideTabPrivate ( CAutoHideTab * _public ) ;
2022-11-01 20:34:08 +08:00
/**
* Update the orientation , visibility and spacing based on the area of
* the side bar
*/
void updateOrientation ( ) ;
2022-11-04 15:51:17 +08:00
/**
* Convenience function to ease dock container access
*/
CDockContainerWidget * dockContainer ( ) const
{
return DockWidget ? DockWidget - > dockContainer ( ) : nullptr ;
}
/**
* Forward this event to the dock container
*/
void forwardEventToDockContainer ( QEvent * event )
{
auto DockContainer = dockContainer ( ) ;
if ( DockContainer )
{
DockContainer - > handleAutoHideWidgetEvent ( event , _this ) ;
}
}
2023-07-07 19:35:55 +08:00
/**
* Helper function to create and initialize the menu entries for
* the " Auto Hide Group To... " menu
*/
QAction * createAutoHideToAction ( const QString & Title , SideBarLocation Location ,
QMenu * Menu )
{
auto Action = Menu - > addAction ( Title ) ;
Action - > setProperty ( " Location " , Location ) ;
QObject : : connect ( Action , & QAction : : triggered , _this , & CAutoHideTab : : onAutoHideToActionClicked ) ;
Action - > setEnabled ( Location ! = _this - > sideBarLocation ( ) ) ;
return Action ;
}
2023-07-07 20:42:13 +08:00
/**
* Test function for current drag state
*/
bool isDraggingState ( eDragState dragState ) const
{
return this - > DragState = = dragState ;
}
/**
* Saves the drag start position in global and local coordinates
*/
void saveDragStartMousePosition ( const QPoint & GlobalPos )
{
GlobalDragStartMousePosition = GlobalPos ;
DragStartMousePosition = _this - > mapFromGlobal ( GlobalPos ) ;
}
/**
* Starts floating of the dock widget that belongs to this title bar
* Returns true , if floating has been started and false if floating
* is not possible for any reason
*/
bool startFloating ( eDragState DraggingState = DraggingFloatingWidget ) ;
template < typename T >
IFloatingWidget * createFloatingWidget ( T * Widget )
{
auto w = new CFloatingDragPreview ( Widget ) ;
_this - > connect ( w , & CFloatingDragPreview : : draggingCanceled , [ = ] ( )
{
DragState = DraggingInactive ;
} ) ;
return w ;
}
2022-09-12 15:55:45 +08:00
} ; // struct DockWidgetTabPrivate
2022-09-05 17:29:42 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
AutoHideTabPrivate : : AutoHideTabPrivate ( CAutoHideTab * _public ) :
2022-09-05 17:29:42 +08:00
_this ( _public )
{
}
2022-11-01 20:34:08 +08:00
//============================================================================
void AutoHideTabPrivate : : updateOrientation ( )
{
2022-11-04 16:41:00 +08:00
bool IconOnly = CDockManager : : testAutoHideConfigFlag ( CDockManager : : AutoHideSideBarsIconOnly ) ;
if ( IconOnly & & ! _this - > icon ( ) . isNull ( ) )
2022-11-01 20:34:08 +08:00
{
_this - > setText ( " " ) ;
_this - > setOrientation ( Qt : : Horizontal ) ;
2022-11-04 16:41:00 +08:00
}
else
{
auto area = SideBar - > sideBarLocation ( ) ;
_this - > setOrientation ( ( area = = SideBarBottom | | area = = SideBarTop ) ? Qt : : Horizontal : Qt : : Vertical ) ;
2022-11-01 20:34:08 +08:00
}
}
2023-07-07 20:42:13 +08:00
//============================================================================
bool AutoHideTabPrivate : : startFloating ( eDragState DraggingState )
{
auto DockArea = DockWidget - > dockAreaWidget ( ) ;
ADS_PRINT ( " isFloating " < < dockContainer - > isFloating ( ) ) ;
ADS_PRINT ( " startFloating " ) ;
DragState = DraggingState ;
IFloatingWidget * FloatingWidget = nullptr ;
FloatingWidget = createFloatingWidget ( DockArea ) ;
auto Size = DockArea - > size ( ) ;
auto StartPos = DragStartMousePosition ;
auto AutoHideContainer = DockWidget - > autoHideDockContainer ( ) ;
switch ( SideBar - > sideBarLocation ( ) )
{
case SideBarLeft :
StartPos . rx ( ) = AutoHideContainer - > rect ( ) . left ( ) + 10 ;
break ;
case SideBarRight :
StartPos . rx ( ) = AutoHideContainer - > rect ( ) . right ( ) - 10 ;
break ;
case SideBarTop :
StartPos . ry ( ) = AutoHideContainer - > rect ( ) . top ( ) + 10 ;
break ;
case SideBarBottom :
StartPos . ry ( ) = AutoHideContainer - > rect ( ) . bottom ( ) - 10 ;
break ;
case SideBarNone :
return false ;
}
FloatingWidget - > startFloating ( StartPos , Size , DraggingFloatingWidget , _this ) ;
auto DockManager = DockWidget - > dockManager ( ) ;
auto Overlay = DockManager - > containerOverlay ( ) ;
Overlay - > setAllowedAreas ( OuterDockAreas ) ;
this - > FloatingWidget = FloatingWidget ;
qApp - > postEvent ( DockWidget , new QEvent ( ( QEvent : : Type ) internal : : DockedWidgetDragStartEvent ) ) ;
return true ;
}
2022-09-05 17:29:42 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
void CAutoHideTab : : setSideBar ( CAutoHideSideBar * SideTabBar )
2022-09-05 17:29:42 +08:00
{
2022-11-01 19:06:59 +08:00
d - > SideBar = SideTabBar ;
2022-11-01 20:34:08 +08:00
if ( d - > SideBar )
{
d - > updateOrientation ( ) ;
}
2022-09-05 17:29:42 +08:00
}
2022-11-15 21:16:01 +08:00
//============================================================================
CAutoHideSideBar * CAutoHideTab : : sideBar ( ) const
{
return d - > SideBar ;
}
2022-09-05 17:29:42 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
void CAutoHideTab : : removeFromSideBar ( )
2022-09-05 17:29:42 +08:00
{
2022-11-01 19:06:59 +08:00
if ( d - > SideBar = = nullptr )
2022-09-05 17:29:42 +08:00
{
return ;
}
2022-11-01 20:34:08 +08:00
d - > SideBar - > removeTab ( this ) ;
2022-11-01 19:06:59 +08:00
setSideBar ( nullptr ) ;
2022-09-05 17:29:42 +08:00
}
//============================================================================
2022-11-01 19:06:59 +08:00
CAutoHideTab : : CAutoHideTab ( QWidget * parent ) :
2022-11-03 22:28:01 +08:00
CPushButton ( parent ) ,
2022-11-01 19:06:59 +08:00
d ( new AutoHideTabPrivate ( this ) )
2022-09-05 17:29:42 +08:00
{
setAttribute ( Qt : : WA_NoMousePropagation ) ;
setFocusPolicy ( Qt : : NoFocus ) ;
}
2022-09-12 15:55:45 +08:00
2022-09-05 17:29:42 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
CAutoHideTab : : ~ CAutoHideTab ( )
2022-09-05 17:29:42 +08:00
{
2022-11-03 23:49:20 +08:00
ADS_PRINT ( " ~CDockWidgetSideTab() " ) ;
2022-09-05 17:29:42 +08:00
delete d ;
}
2022-09-12 15:55:45 +08:00
2022-09-05 17:29:42 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
void CAutoHideTab : : updateStyle ( )
2022-09-05 17:29:42 +08:00
{
2022-10-28 21:20:56 +08:00
internal : : repolishStyle ( this , internal : : RepolishDirectChildren ) ;
2022-10-25 21:51:38 +08:00
update ( ) ;
2022-09-05 17:29:42 +08:00
}
2022-09-08 11:30:56 +08:00
2022-09-12 15:55:45 +08:00
//============================================================================
2022-11-01 20:34:08 +08:00
SideBarLocation CAutoHideTab : : sideBarLocation ( ) const
2022-09-08 11:30:56 +08:00
{
2022-11-01 19:06:59 +08:00
if ( d - > SideBar )
2022-09-08 11:30:56 +08:00
{
2022-11-01 20:34:08 +08:00
return d - > SideBar - > sideBarLocation ( ) ;
2022-09-08 11:30:56 +08:00
}
2022-11-03 22:28:01 +08:00
return SideBarLeft ;
2022-09-08 11:30:56 +08:00
}
2022-09-12 15:55:45 +08:00
2022-10-26 15:51:37 +08:00
2022-09-12 15:55:45 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
void CAutoHideTab : : setOrientation ( Qt : : Orientation Orientation )
2022-09-13 10:42:58 +08:00
{
d - > Orientation = Orientation ;
2022-11-03 18:34:04 +08:00
if ( orientation ( ) = = Qt : : Horizontal )
{
setSizePolicy ( QSizePolicy : : Minimum , QSizePolicy : : Fixed ) ;
}
else
{
setSizePolicy ( QSizePolicy : : Fixed , QSizePolicy : : Minimum ) ;
}
2022-10-26 15:51:37 +08:00
CPushButton : : setButtonOrientation ( ( Qt : : Horizontal = = Orientation )
2022-10-18 22:43:39 +08:00
? CPushButton : : Horizontal : CPushButton : : VerticalTopToBottom ) ;
2022-09-13 14:21:01 +08:00
updateStyle ( ) ;
2022-09-13 10:42:58 +08:00
}
2022-10-26 15:51:37 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
Qt : : Orientation CAutoHideTab : : orientation ( ) const
2022-10-26 15:51:37 +08:00
{
return d - > Orientation ;
}
2022-10-14 21:32:05 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
bool CAutoHideTab : : isActiveTab ( ) const
2022-10-14 21:32:05 +08:00
{
2022-10-28 22:28:23 +08:00
if ( d - > DockWidget & & d - > DockWidget - > autoHideDockContainer ( ) )
2022-10-14 21:32:05 +08:00
{
return d - > DockWidget - > autoHideDockContainer ( ) - > isVisible ( ) ;
}
return false ;
}
2022-09-14 17:39:57 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
CDockWidget * CAutoHideTab : : dockWidget ( ) const
2022-09-14 17:39:57 +08:00
{
return d - > DockWidget ;
}
2022-10-28 22:28:23 +08:00
//============================================================================
2022-11-01 19:06:59 +08:00
void CAutoHideTab : : setDockWidget ( CDockWidget * DockWidget )
2022-10-28 22:28:23 +08:00
{
if ( ! DockWidget )
{
return ;
}
d - > DockWidget = DockWidget ;
setText ( DockWidget - > windowTitle ( ) ) ;
2022-10-31 02:44:33 +08:00
setIcon ( d - > DockWidget - > icon ( ) ) ;
2022-11-05 17:14:01 +08:00
setToolTip ( DockWidget - > windowTitle ( ) ) ;
2022-10-28 22:28:23 +08:00
}
2022-11-04 15:51:17 +08:00
//============================================================================
2022-11-04 17:45:09 +08:00
bool CAutoHideTab : : event ( QEvent * event )
2022-11-04 15:51:17 +08:00
{
2022-11-07 17:15:14 +08:00
if ( ! CDockManager : : testAutoHideConfigFlag ( CDockManager : : AutoHideShowOnMouseOver ) )
{
return Super : : event ( event ) ;
}
2022-11-04 17:45:09 +08:00
switch ( event - > type ( ) )
{
case QEvent : : Enter :
case QEvent : : Leave :
d - > forwardEventToDockContainer ( event ) ;
break ;
default :
break ;
}
return Super : : event ( event ) ;
2022-11-04 15:51:17 +08:00
}
2023-07-07 17:21:54 +08:00
2022-11-04 17:22:10 +08:00
//============================================================================
bool CAutoHideTab : : iconOnly ( ) const
{
return CDockManager : : testAutoHideConfigFlag ( CDockManager : : AutoHideSideBarsIconOnly ) & & ! icon ( ) . isNull ( ) ;
}
2023-07-07 17:21:54 +08:00
//============================================================================
void CAutoHideTab : : contextMenuEvent ( QContextMenuEvent * ev )
{
ev - > accept ( ) ;
//d->saveDragStartMousePosition(ev->globalPos());
const bool isFloatable = d - > DockWidget - > features ( ) . testFlag ( CDockWidget : : DockWidgetFloatable ) ;
QAction * Action ;
QMenu Menu ( this ) ;
Action = Menu . addAction ( tr ( " Detach " ) , this , SLOT ( setDockWidgetFloating ( ) ) ) ;
Action - > setEnabled ( isFloatable ) ;
auto IsPinnable = d - > DockWidget - > features ( ) . testFlag ( CDockWidget : : DockWidgetPinnable ) ;
Action - > setEnabled ( IsPinnable ) ;
auto menu = Menu . addMenu ( tr ( " Pin To... " ) ) ;
menu - > setEnabled ( IsPinnable ) ;
2023-07-07 19:35:55 +08:00
d - > createAutoHideToAction ( tr ( " Top " ) , SideBarTop , menu ) ;
d - > createAutoHideToAction ( tr ( " Left " ) , SideBarLeft , menu ) ;
d - > createAutoHideToAction ( tr ( " Right " ) , SideBarRight , menu ) ;
d - > createAutoHideToAction ( tr ( " Bottom " ) , SideBarBottom , menu ) ;
2023-07-07 17:21:54 +08:00
/*Menu.addSeparator();
Action = Menu . addAction ( tr ( " Close " ) , this , SIGNAL ( closeRequested ( ) ) ) ;
Action - > setEnabled ( isClosable ( ) ) ;
if ( d - > DockArea - > openDockWidgetsCount ( ) > 1 )
{
Action = Menu . addAction ( tr ( " Close Others " ) , this , SIGNAL ( closeOtherTabsRequested ( ) ) ) ;
} */
Menu . exec ( ev - > globalPos ( ) ) ;
}
//============================================================================
2023-07-07 19:35:55 +08:00
void CAutoHideTab : : setDockWidgetFloating ( )
2023-07-07 17:21:54 +08:00
{
2023-07-07 19:35:55 +08:00
/*auto DockArea = dockWidget()->dockAreaWidget();
auto AutoHideContainer = dockWidget ( ) - > autoHideDockContainer ( ) ;
auto OriginalSize = AutoHideContainer - > originalDockWidgetSize ( ) ;
auto DockAreaSize = DockArea - > size ( ) ;
if ( ads : : internal : : isHorizontalSideBarLocation ( sideBarLocation ( ) ) )
2023-07-07 17:21:54 +08:00
{
2023-07-07 19:35:55 +08:00
DockAreaSize . setHeight ( OriginalSize . height ( ) ) ;
2023-07-07 17:21:54 +08:00
}
2023-07-07 19:35:55 +08:00
else
{
DockAreaSize . setWidth ( OriginalSize . width ( ) ) ;
}
DockArea - > resize ( DockAreaSize ) ; */
dockWidget ( ) - > setFloating ( ) ;
2023-07-07 17:21:54 +08:00
}
2023-07-07 19:35:55 +08:00
//===========================================================================
void CAutoHideTab : : onAutoHideToActionClicked ( )
2023-07-07 17:21:54 +08:00
{
2023-07-07 19:35:55 +08:00
int Location = sender ( ) - > property ( LocationProperty ) . toInt ( ) ;
std : : cout < < " CAutoHideTab::onAutoHideToActionClicked " < < Location < < std : : endl ;
d - > DockWidget - > setAutoHide ( true , ( SideBarLocation ) Location ) ;
2023-07-07 17:21:54 +08:00
}
2023-07-07 20:42:13 +08:00
//============================================================================
void CAutoHideTab : : mousePressEvent ( QMouseEvent * ev )
{
// If AutoHideShowOnMouseOver is active, then the showing is triggered
// by a MousePressEvent sent to this tab. To prevent accidental hiding
// of the tab by a mouse click, we wait at least 500 ms before we accept
// the mouse click
if ( ! ev - > spontaneous ( ) )
{
d - > TimeSinceHoverMousePress . restart ( ) ;
d - > forwardEventToDockContainer ( ev ) ;
}
else if ( d - > TimeSinceHoverMousePress . hasExpired ( 500 ) )
{
d - > forwardEventToDockContainer ( ev ) ;
}
if ( ev - > button ( ) = = Qt : : LeftButton )
{
ev - > accept ( ) ;
d - > MousePressed = true ;
d - > saveDragStartMousePosition ( internal : : globalPositionOf ( ev ) ) ;
d - > DragState = DraggingMousePressed ;
}
Super : : mousePressEvent ( ev ) ;
}
//============================================================================
void CAutoHideTab : : mouseReleaseEvent ( QMouseEvent * ev )
{
if ( ev - > button ( ) = = Qt : : LeftButton )
{
d - > MousePressed = false ;
auto CurrentDragState = d - > DragState ;
d - > GlobalDragStartMousePosition = QPoint ( ) ;
d - > DragStartMousePosition = QPoint ( ) ;
d - > DragState = DraggingInactive ;
switch ( CurrentDragState )
{
case DraggingTab :
// End of tab moving, emit signal
/*if (d->DockArea)
{
ev - > accept ( ) ;
Q_EMIT moved ( internal : : globalPositionOf ( ev ) ) ;
} */
break ;
case DraggingFloatingWidget :
ev - > accept ( ) ;
d - > FloatingWidget - > finishDragging ( ) ;
break ;
default :
/*if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
d - > focusController ( ) - > setDockWidgetTabPressed ( false ) ;
} */
break ; // do nothing
}
}
Super : : mouseReleaseEvent ( ev ) ;
}
//============================================================================
void CAutoHideTab : : mouseMoveEvent ( QMouseEvent * ev )
{
std : : cout < < " CAutoHideTab::mouseMoveEvent " < < std : : endl ;
if ( ! ( ev - > buttons ( ) & Qt : : LeftButton ) | | d - > isDraggingState ( DraggingInactive ) )
{
d - > DragState = DraggingInactive ;
Super : : mouseMoveEvent ( ev ) ;
return ;
}
// move floating window
if ( d - > isDraggingState ( DraggingFloatingWidget ) )
{
d - > FloatingWidget - > moveFloating ( ) ;
Super : : mouseMoveEvent ( ev ) ;
return ;
}
// move tab
if ( d - > isDraggingState ( DraggingTab ) )
{
// Moving the tab is always allowed because it does not mean moving the
// dock widget around
//d->moveTab(ev);
}
auto MappedPos = mapToParent ( ev - > pos ( ) ) ;
bool MouseOutsideBar = ( MappedPos . x ( ) < 0 ) | | ( MappedPos . x ( ) > parentWidget ( ) - > rect ( ) . right ( ) ) ;
// Maybe a fixed drag distance is better here ?
int DragDistanceY = qAbs ( d - > GlobalDragStartMousePosition . y ( ) - internal : : globalPositionOf ( ev ) . y ( ) ) ;
std : : cout < < " DragDistanceY " < < DragDistanceY < < " MouseOutsideBar " < < MouseOutsideBar < < std : : endl ;
if ( DragDistanceY > = CDockManager : : startDragDistance ( ) | | MouseOutsideBar )
{
// Floating is only allowed for widgets that are floatable
// We can create the drag preview if the widget is movable.
auto Features = d - > DockWidget - > features ( ) ;
if ( Features . testFlag ( CDockWidget : : DockWidgetFloatable ) | | ( Features . testFlag ( CDockWidget : : DockWidgetMovable ) ) )
{
// If we undock, we need to restore the initial position of this
// tab because it looks strange if it remains on its dragged position
/*if (d->isDraggingState(DraggingTab))
{
parentWidget ( ) - > layout ( ) - > update ( ) ;
} */
d - > startFloating ( ) ;
}
return ;
}
/*else if (d->DockArea->openDockWidgetsCount() > 1
& & ( internal : : globalPositionOf ( ev ) - d - > GlobalDragStartMousePosition ) . manhattanLength ( ) > = QApplication : : startDragDistance ( ) ) // Wait a few pixels before start moving
{
// If we start dragging the tab, we save its inital position to
// restore it later
if ( DraggingTab ! = d - > DragState )
{
d - > TabDragStartPosition = this - > pos ( ) ;
}
d - > DragState = DraggingTab ;
return ;
} */
Super : : mouseMoveEvent ( ev ) ;
}
2022-09-05 17:29:42 +08:00
}