1) There is a problem in that floating frames are not currently supported with !mRealTimeUpdates. We wrote a patch to correct this problem. You will find it attached to this posting. Here is a description of what was changed and why. In cbBarDragPlugin::ShowHint(), SetBarState is called every time mpCurPane changes. This is correct. However, this also happens every time, even if mRealTimeUpdates is false. The state should not be changed during the drag operation if mRealTimeUpdates is off. This is corrected in this patch. Code was also added in cbBarDragPlugin::OnLButtonUp() to actually do the state changing, only if mRealTimeUpdates is off. Normally, this is performed in ShowHint if mRealTimeUpdates is on. I also took the liberty of changing the drag cursor back to an arrow. This is the way it is in MS Visual C++, and it looks way better. The MoveWindow cursor looks terrible, IMHO. When FL gets the embedded cursor code working, we can switch back to a hand or something else. 2) This time we have discovered a crash bug in FL. The steps to reproduce this bug are as follows: 1. Open up a pane, dock it. 2. Click the Expand button (arrow button) in the frame hints portion 3. Click it again to Collapse the pane. 4. Now click the close button of the pane. Crash. We investigated what was causing this problem, and it turns out that the button state never gets unset. Once a button is pressed, it is always pressed. Thus, when the expand/ collapse button is pressed, and then the close button is pressed, the pane will close, but then FL will also try to expand or collapse the pane as well, because it thinks that the expand/collapse button was set. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15802 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
965 lines
22 KiB
C++
965 lines
22 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: bardragpl.cpp
|
|
// Purpose: cbBarDragPlugin implementation
|
|
// Author: Aleksandras Gluchovas
|
|
// Modified by:
|
|
// Created: 23/09/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Aleksandras Gluchovas
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation "bardragpl.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#include "wx/fl/bardragpl.h"
|
|
|
|
#define POS_UNDEFINED -32768
|
|
|
|
// helpers, FOR NOW:: static
|
|
|
|
static inline bool rect_hits_rect( const wxRect& r1, const wxRect& r2 )
|
|
{
|
|
if ( ( r2.x >= r1.x && r2.x <= r1.x + r1.width ) ||
|
|
( r1.x >= r2.x && r1.x <= r2.x + r2.width ) )
|
|
|
|
if ( ( r2.y >= r1.y && r2.y <= r1.y + r1.height ) ||
|
|
( r1.y >= r2.y && r1.y <= r2.y + r2.height ) )
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static inline bool rect_contains_point( const wxRect& rect, int x, int y )
|
|
{
|
|
return ( x >= rect.x &&
|
|
y >= rect.y &&
|
|
x < rect.x + rect.width &&
|
|
y < rect.y + rect.height );
|
|
}
|
|
|
|
/***** Implementation for class cbBarDragPlugin *****/
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS( cbBarDragPlugin, cbPluginBase )
|
|
|
|
BEGIN_EVENT_TABLE( cbBarDragPlugin, cbPluginBase )
|
|
|
|
//EVT_PL_LEFT_DOWN ( cbBarDragPlugin::OnLButtonDown )
|
|
EVT_PL_LEFT_UP ( cbBarDragPlugin::OnLButtonUp )
|
|
EVT_PL_MOTION ( cbBarDragPlugin::OnMouseMove )
|
|
EVT_PL_DRAW_HINT_RECT ( cbBarDragPlugin::OnDrawHintRect )
|
|
EVT_PL_START_BAR_DRAGGING ( cbBarDragPlugin::OnStartBarDragging )
|
|
EVT_PL_LEFT_DCLICK ( cbBarDragPlugin::OnLDblClick )
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
cbBarDragPlugin::cbBarDragPlugin(void)
|
|
|
|
: mBarDragStarted ( FALSE ),
|
|
mCanStick ( TRUE ),
|
|
mpScrDc ( NULL ),
|
|
mpCurCursor ( NULL ),
|
|
mpDraggedBar ( NULL ),
|
|
mInClientHintBorder( 4 )
|
|
{}
|
|
|
|
cbBarDragPlugin::cbBarDragPlugin( wxFrameLayout* pPanel, int paneMask )
|
|
|
|
: cbPluginBase( pPanel, paneMask ),
|
|
|
|
mBarDragStarted ( FALSE ),
|
|
mCanStick ( TRUE ),
|
|
mpScrDc ( NULL ),
|
|
mpCurCursor ( NULL ),
|
|
mpDraggedBar ( NULL ),
|
|
mInClientHintBorder( 4 )
|
|
{}
|
|
|
|
cbBarDragPlugin::~cbBarDragPlugin()
|
|
{
|
|
// nothing
|
|
}
|
|
|
|
// helper methods (protected)
|
|
|
|
// clips (top/bottom) or (right/left) edges against the frame's bounding rect.
|
|
|
|
void do_clip_edges( int len, int& rectPos, int& rectLen )
|
|
{
|
|
if ( rectPos < 0 )
|
|
{
|
|
rectLen += rectPos;
|
|
rectPos = 0;
|
|
if ( rectLen < 0 )
|
|
rectLen = 1;
|
|
}
|
|
else
|
|
if ( rectPos > len-1 )
|
|
{
|
|
rectPos = len-1;
|
|
rectLen = 1;
|
|
}
|
|
else
|
|
if ( rectPos + rectLen - 1 > len )
|
|
|
|
rectLen -= (rectPos + rectLen) - len + 1;
|
|
}
|
|
|
|
void cbBarDragPlugin::ClipRectInFrame( wxRect& rect )
|
|
{
|
|
int w, h;
|
|
mpLayout->GetParentFrame().GetClientSize( &w, &h );
|
|
|
|
do_clip_edges( w, rect.x, rect.width );
|
|
do_clip_edges( h, rect.y, rect.height );
|
|
}
|
|
|
|
void cbBarDragPlugin::ClipPosInFrame( wxPoint& pos )
|
|
{
|
|
int w, h;
|
|
mpLayout->GetParentFrame().GetClientSize( &w, &h );
|
|
|
|
if ( pos.x < 0 )
|
|
pos.x = 0;
|
|
if ( pos.y < 0 )
|
|
pos.y = 0;
|
|
if ( pos.x > w )
|
|
pos.x = w-1;
|
|
if ( pos.y > h )
|
|
pos.y = h-1;
|
|
}
|
|
|
|
void cbBarDragPlugin::AdjustHintRect( wxPoint& mousePos )
|
|
{
|
|
mHintRect.x = mousePos.x - mMouseInRectX;
|
|
mHintRect.y = mousePos.y - mMouseInRectY;
|
|
}
|
|
|
|
cbDockPane* cbBarDragPlugin::HitTestPanes( wxRect& rect )
|
|
{
|
|
//wxRect clipped = rect;
|
|
|
|
//ClipRectInFrame( clipped );
|
|
|
|
cbDockPane** pPanes = mpLayout->GetPanesArray();
|
|
|
|
for( int i = 0; i != MAX_PANES; ++i )
|
|
|
|
if ( rect_hits_rect( pPanes[i]->mBoundsInParent, rect ) )
|
|
|
|
return pPanes[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
cbDockPane* cbBarDragPlugin::HitTestPanes( wxPoint& pos )
|
|
{
|
|
wxPoint clipped = pos;
|
|
|
|
//ClipPosInFrame( pos );
|
|
|
|
cbDockPane** pPanes = mpLayout->GetPanesArray();
|
|
|
|
for( int i = 0; i != MAX_PANES; ++i )
|
|
|
|
if ( rect_contains_point( pPanes[i]->mBoundsInParent, clipped.x, clipped.y ) )
|
|
|
|
return pPanes[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool cbBarDragPlugin::HitsPane( cbDockPane* pPane, wxRect& rect )
|
|
{
|
|
return rect_hits_rect( pPane->mBoundsInParent, rect );
|
|
}
|
|
|
|
int cbBarDragPlugin::GetDistanceToPane( cbDockPane* pPane, wxPoint& mousePos )
|
|
{
|
|
wxRect& bounds = pPane->mBoundsInParent;
|
|
|
|
switch( pPane->mAlignment )
|
|
{
|
|
case FL_ALIGN_TOP : return mousePos.y - ( bounds.y + bounds.height );
|
|
|
|
case FL_ALIGN_BOTTOM : return bounds.y - mousePos.y;
|
|
|
|
case FL_ALIGN_LEFT : return mousePos.x - ( bounds.x + bounds.width );
|
|
|
|
case FL_ALIGN_RIGHT : return bounds.x - mousePos.x;
|
|
|
|
default : return 0; // never reached
|
|
}
|
|
|
|
// return 0;
|
|
}
|
|
|
|
bool cbBarDragPlugin::IsInOtherPane( wxPoint& mousePos )
|
|
{
|
|
cbDockPane* pPane = HitTestPanes( mousePos );
|
|
|
|
if ( pPane && pPane != mpCurPane ) return TRUE;
|
|
else return FALSE;
|
|
}
|
|
|
|
bool cbBarDragPlugin::IsInClientArea( wxPoint& mousePos )
|
|
{
|
|
return ( HitTestPanes( mousePos ) == NULL );
|
|
}
|
|
|
|
bool cbBarDragPlugin::IsInClientArea( wxRect& rect )
|
|
{
|
|
return ( HitTestPanes( rect ) == NULL );
|
|
}
|
|
|
|
void cbBarDragPlugin::CalcOnScreenDims( wxRect& rect )
|
|
{
|
|
if ( !mpCurPane || mpDraggedBar->IsFixed() ) return;
|
|
|
|
wxRect inPane = rect;
|
|
|
|
mpCurPane->FrameToPane( &inPane );
|
|
|
|
int rowNo = mpCurPane->GetRowAt( inPane.y, inPane.y + inPane.height );
|
|
|
|
bool isMaximized = ( rowNo >= (int)mpCurPane->GetRowList().Count() || rowNo < 0 );
|
|
|
|
if ( isMaximized )
|
|
{
|
|
inPane.x = 0;
|
|
inPane.width = mpCurPane->mPaneWidth;
|
|
|
|
mpCurPane->PaneToFrame( &inPane );
|
|
|
|
rect = inPane;
|
|
}
|
|
}
|
|
|
|
// helpers
|
|
|
|
static inline void check_upper_overrun( int& pos, int width, int mousePos )
|
|
{
|
|
if ( mousePos >= pos + width )
|
|
|
|
pos = mousePos - width/2;
|
|
}
|
|
|
|
static inline void check_lower_overrun( int& pos, int width, int mousePos )
|
|
{
|
|
if ( mousePos <= pos )
|
|
|
|
pos = mousePos - width/2;
|
|
}
|
|
|
|
void cbBarDragPlugin::StickToPane( cbDockPane* pPane, wxPoint& mousePos )
|
|
{
|
|
int wInPane = GetBarWidthInPane ( pPane );
|
|
int hInPane = GetBarHeightInPane( pPane );
|
|
|
|
// adjsut hint-rect horizontally (in pane's orientation)
|
|
|
|
if ( pPane->IsHorizontal() )
|
|
{
|
|
mHintRect.width = wInPane;
|
|
mHintRect.height = hInPane;
|
|
}
|
|
else
|
|
{
|
|
mHintRect.height = wInPane;
|
|
mHintRect.width = hInPane;
|
|
}
|
|
|
|
// adjsut hint-rect vertically (in pane's orientation)
|
|
|
|
wxRect& bounds = pPane->mBoundsInParent;
|
|
|
|
// TRUE, if hint enters the pane through it's lower edge
|
|
|
|
bool fromLowerEdge = ( pPane->IsHorizontal() )
|
|
? mousePos.y > bounds.y
|
|
: mousePos.x > bounds.x;
|
|
|
|
// NOTE:: about all the below min/max things: they are meant to ensure
|
|
// that the mouse pointer doesn't overrun (leave) the hint-rectangle
|
|
// when its dimensions are recalculated upon sticking it to the pane
|
|
|
|
if ( pPane->IsHorizontal() && fromLowerEdge )
|
|
{
|
|
int paneBottomEdgeY = bounds.y + bounds.height;
|
|
|
|
mHintRect.y = wxMin( paneBottomEdgeY, mousePos.y );
|
|
|
|
check_lower_overrun( mHintRect.y, hInPane, mousePos.y );
|
|
|
|
}
|
|
else
|
|
if ( pPane->IsHorizontal() && !fromLowerEdge )
|
|
{
|
|
int paneTopEdgeY = bounds.y;
|
|
|
|
mHintRect.y = wxMax( paneTopEdgeY - hInPane, mousePos.y - hInPane );
|
|
|
|
check_upper_overrun( mHintRect.y, hInPane, mousePos.y );
|
|
}
|
|
else
|
|
if ( !pPane->IsHorizontal() && fromLowerEdge )
|
|
{
|
|
int paneRightEdgeX = bounds.x + bounds.width;
|
|
|
|
mHintRect.x = wxMin( paneRightEdgeX, mousePos.x );
|
|
|
|
check_lower_overrun( mHintRect.x, hInPane, mousePos.x );
|
|
}
|
|
else
|
|
if ( !pPane->IsHorizontal() && !fromLowerEdge )
|
|
{
|
|
int paneLeftEdgeX = bounds.x;
|
|
|
|
mHintRect.x = wxMax( paneLeftEdgeX - hInPane, mousePos.x - hInPane );
|
|
|
|
check_upper_overrun( mHintRect.x, hInPane, mousePos.x );
|
|
}
|
|
|
|
mMouseInRectX = mousePos.x - mHintRect.x;
|
|
mMouseInRectY = mousePos.y - mHintRect.y;
|
|
|
|
mpCurPane = pPane; // memorize pane to which the hint is currently sticked
|
|
}
|
|
|
|
void cbBarDragPlugin::UnstickFromPane( cbDockPane* pPane, wxPoint& mousePos )
|
|
{
|
|
// unsticking causes rectangle to get the shape in which
|
|
// dragged control-bar would be when floated
|
|
|
|
int newWidth = mpDraggedBar->mDimInfo.mSizes[wxCBAR_FLOATING].x;
|
|
int newHeight = mpDraggedBar->mDimInfo.mSizes[wxCBAR_FLOATING].y;
|
|
|
|
wxRect& flBounds = mpDraggedBar->mDimInfo.mBounds[wxCBAR_FLOATING];
|
|
|
|
if ( flBounds.width != -1 )
|
|
{
|
|
newWidth = flBounds.width;
|
|
newHeight = flBounds.height;
|
|
}
|
|
|
|
mHintRect.width = newWidth;
|
|
mHintRect.height = newHeight;
|
|
|
|
wxRect& bounds = pPane->mBoundsInParent;
|
|
|
|
// TRUE, if hint leaves the pane through it's lower edge
|
|
|
|
bool fromLowerEdge = ( pPane->IsHorizontal() )
|
|
? mousePos.y > bounds.y
|
|
: mousePos.x > bounds.x;
|
|
|
|
// NOTE:: ...all the below min/max things - see comments about it in StickToPane(..)
|
|
|
|
if ( pPane->IsHorizontal() && fromLowerEdge )
|
|
{
|
|
// bool fromLowerEdge = mousePos.y > bounds.y;
|
|
|
|
mHintRect.y = wxMax( bounds.y + bounds.height + 1, mousePos.y - newHeight );
|
|
|
|
check_upper_overrun( mHintRect.y, newHeight, mousePos.y );
|
|
|
|
// this is how MFC's hint behaves:
|
|
|
|
if ( mMouseInRectX > newWidth )
|
|
|
|
mHintRect.x = mousePos.x - ( newWidth / 2 );
|
|
}
|
|
else
|
|
if ( pPane->IsHorizontal() && !fromLowerEdge )
|
|
{
|
|
mHintRect.y = wxMin( bounds.y - newHeight - 1, mousePos.y );
|
|
|
|
// -/-
|
|
|
|
if ( mMouseInRectX > newWidth )
|
|
|
|
mHintRect.x = mousePos.x - ( newWidth / 2 );
|
|
|
|
check_lower_overrun( mHintRect.y, newHeight, mousePos.y );
|
|
}
|
|
else
|
|
if ( !pPane->IsHorizontal() && fromLowerEdge )
|
|
{
|
|
mHintRect.x = wxMax( bounds.x + bounds.width, mousePos.x - newWidth );
|
|
|
|
// -/-
|
|
|
|
if ( mMouseInRectY > newHeight )
|
|
|
|
mHintRect.y = mousePos.y - ( newHeight / 2 );
|
|
|
|
check_upper_overrun( mHintRect.x, newWidth, mousePos.x );
|
|
}
|
|
else
|
|
if ( !pPane->IsHorizontal() && !fromLowerEdge )
|
|
{
|
|
mHintRect.x = wxMin( bounds.x - newWidth - 1, mousePos.x );
|
|
|
|
// -/-
|
|
|
|
if ( mMouseInRectY > newHeight )
|
|
|
|
mHintRect.y = mousePos.y - ( newHeight / 2 );
|
|
|
|
check_lower_overrun( mHintRect.x, newWidth, mousePos.x );
|
|
}
|
|
|
|
mMouseInRectX = mousePos.x - mHintRect.x;
|
|
mMouseInRectY = mousePos.y - mHintRect.y;
|
|
|
|
mpCurPane = NULL;
|
|
}
|
|
|
|
int cbBarDragPlugin::GetBarWidthInPane( cbDockPane* pPane )
|
|
{
|
|
if ( pPane == mpSrcPane )
|
|
|
|
return mBarWidthInSrcPane;
|
|
|
|
// this is how MFC's bars behave:
|
|
|
|
if ( pPane->IsHorizontal() )
|
|
|
|
return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_HORIZONTALLY].x;
|
|
else
|
|
return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_VERTICALLY ].x;
|
|
}
|
|
|
|
int cbBarDragPlugin::GetBarHeightInPane( cbDockPane* pPane )
|
|
{
|
|
if ( pPane->IsHorizontal() )
|
|
|
|
return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_HORIZONTALLY].y;
|
|
else
|
|
return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_VERTICALLY ].y;
|
|
}
|
|
|
|
void cbBarDragPlugin::ShowHint( bool prevWasInClient )
|
|
{
|
|
bool wasDocked = FALSE;
|
|
|
|
|
|
if ( mpSrcPane->mProps.mRealTimeUpdatesOn == FALSE )
|
|
{
|
|
// do heavy calculations first
|
|
|
|
wxRect actualRect = mHintRect; // will be adjusted depending on drag-settings
|
|
|
|
if ( mpSrcPane->mProps.mExactDockPredictionOn && mpCurPane )
|
|
{
|
|
bool success = mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane, FALSE );
|
|
|
|
wxASSERT( success ); // DBG::
|
|
|
|
actualRect = mpDraggedBar->mBounds;
|
|
|
|
mpCurPane->PaneToFrame( &actualRect );
|
|
}
|
|
else
|
|
CalcOnScreenDims( actualRect );
|
|
|
|
// release previous hint
|
|
|
|
if ( mPrevHintRect.x != POS_UNDEFINED )
|
|
{
|
|
// erase previous rectangle
|
|
|
|
cbDrawHintRectEvent evt( mPrevHintRect, prevWasInClient, TRUE, FALSE );
|
|
|
|
mpLayout->FirePluginEvent( evt );
|
|
}
|
|
|
|
// draw new hint
|
|
|
|
cbDrawHintRectEvent evt( actualRect, mpCurPane == NULL, FALSE, FALSE );
|
|
|
|
mpLayout->FirePluginEvent( evt );
|
|
|
|
mPrevHintRect = actualRect;
|
|
}
|
|
else
|
|
{
|
|
// otherwise, if real-time updates option is ON
|
|
|
|
if ( mpDraggedBar->mState != wxCBAR_FLOATING && !mpCurPane )
|
|
{
|
|
mpLayout->SetBarState( mpDraggedBar, wxCBAR_FLOATING, TRUE );
|
|
}
|
|
else
|
|
if ( mpDraggedBar->mState == wxCBAR_FLOATING && mpCurPane )
|
|
{
|
|
mpLayout->SetBarState( mpDraggedBar, wxCBAR_DOCKED_HORIZONTALLY, FALSE );
|
|
|
|
wasDocked = TRUE;
|
|
}
|
|
|
|
if ( mpCurPane )
|
|
{
|
|
mpLayout->GetUpdatesManager().OnStartChanges();
|
|
|
|
if ( wasDocked )
|
|
|
|
mpDraggedBar->mUMgrData.SetDirty( TRUE );
|
|
|
|
bool success = mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane, FALSE );
|
|
|
|
wxASSERT( success ); // DBG ::
|
|
|
|
mpLayout->GetUpdatesManager().OnFinishChanges();
|
|
mpLayout->GetUpdatesManager().UpdateNow();
|
|
}
|
|
else
|
|
{
|
|
if ( mpLayout->mFloatingOn )
|
|
{
|
|
// move the top-most floated bar around as user drags the hint
|
|
|
|
mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ] = mHintRect;
|
|
|
|
mpLayout->ApplyBarProperties( mpDraggedBar );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*** event handlers ***/
|
|
|
|
void cbBarDragPlugin::OnMouseMove( cbMotionEvent& event )
|
|
{
|
|
// calculate postion in frame's coordiantes
|
|
|
|
if ( !mBarDragStarted )
|
|
{
|
|
event.Skip(); // pass event to the next plugin
|
|
return;
|
|
}
|
|
|
|
wxPoint mousePos = event.mPos;
|
|
|
|
event.mpPane->PaneToFrame( &mousePos.x, &mousePos.y );
|
|
|
|
bool prevIsInClient = ( mpCurPane == 0 );
|
|
|
|
AdjustHintRect( mousePos );
|
|
|
|
// if the hint-rect is not "tempted" to any pane yet
|
|
|
|
if ( mpCurPane == NULL )
|
|
{
|
|
cbDockPane* pPane = HitTestPanes( mHintRect );
|
|
|
|
if ( !pPane )
|
|
|
|
// enable sticking again, if we've left the pane completely
|
|
mCanStick = TRUE;
|
|
|
|
if ( mCanStick && pPane &&
|
|
GetDistanceToPane( pPane, mousePos ) < GetBarHeightInPane( pPane ) )
|
|
|
|
StickToPane( pPane, mousePos );
|
|
else
|
|
if ( pPane && HitTestPanes( mousePos ) == pPane && 0 ) // FOR NOW:: disabled
|
|
|
|
StickToPane( pPane, mousePos );
|
|
}
|
|
else
|
|
{
|
|
// otherwise, when rect is now sticked to some of the panes
|
|
// check if it should still remain in this pane
|
|
|
|
mCanStick = TRUE;
|
|
|
|
bool mouseInOther = IsInOtherPane( mousePos );
|
|
|
|
if ( mouseInOther )
|
|
{
|
|
cbDockPane* pPane = HitTestPanes( mousePos );
|
|
|
|
StickToPane( pPane, mousePos );
|
|
}
|
|
else
|
|
{
|
|
if ( IsInClientArea( mousePos ) )
|
|
{
|
|
cbDockPane* pPane = HitTestPanes( mHintRect );
|
|
|
|
if ( pPane &&
|
|
pPane != mpCurPane &&
|
|
GetDistanceToPane( pPane, mousePos ) < GetBarHeightInPane( pPane ) )
|
|
|
|
StickToPane( pPane, mousePos );
|
|
else
|
|
if ( !pPane )
|
|
{
|
|
UnstickFromPane( mpCurPane, mousePos );
|
|
|
|
// FOR NOW:: disabled, would cause some mess
|
|
//mCanStick = FALSE; // prevents from sticking to this
|
|
// pane again, flag is reset when hint-rect
|
|
// leaves the pane completely
|
|
}
|
|
else
|
|
if ( GetDistanceToPane( pPane, mousePos ) > GetBarHeightInPane( pPane ) )
|
|
{
|
|
if ( !HitsPane( mpCurPane, mHintRect ) )
|
|
{
|
|
UnstickFromPane( mpCurPane, mousePos );
|
|
|
|
// FOR NOW:: disabled, would cause some mess
|
|
//mCanStick = FALSE; // prevents from sticking to this
|
|
// pane again, flag is reset when hint-rect
|
|
// leaves the pane completely
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
ShowHint( prevIsInClient );
|
|
|
|
wxCursor* pPrevCurs = mpCurCursor;
|
|
|
|
if ( mpCurPane )
|
|
{
|
|
mpCurCursor = mpLayout->mpNormalCursor;
|
|
}
|
|
else
|
|
{
|
|
// if floating is off, and we are in the client
|
|
// area, the cursor will be invalid, otherwise
|
|
// it will be the normal cursor
|
|
|
|
if (mpLayout->mFloatingOn)
|
|
{
|
|
mpCurCursor = mpLayout->mpNormalCursor;
|
|
}
|
|
else
|
|
{
|
|
mpCurCursor = mpLayout->mpNECursor;
|
|
}
|
|
|
|
}
|
|
if ( pPrevCurs != mpCurCursor )
|
|
mpLayout->GetParentFrame().SetCursor( *mpCurCursor );
|
|
}
|
|
|
|
void cbBarDragPlugin::OnLButtonDown( cbLeftDownEvent& event )
|
|
{
|
|
if ( mBarDragStarted )
|
|
{
|
|
wxMessageBox("DblClick!");
|
|
}
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void cbBarDragPlugin::OnLButtonUp( cbLeftUpEvent& event )
|
|
{
|
|
if ( mBarDragStarted )
|
|
{
|
|
if ( mpSrcPane->mProps.mRealTimeUpdatesOn == FALSE )
|
|
{
|
|
// erase current rectangle, and finsih on-screen drawing session
|
|
|
|
cbDrawHintRectEvent evt( mPrevHintRect, mpCurPane == NULL, TRUE, TRUE );
|
|
|
|
mpLayout->FirePluginEvent( evt );
|
|
|
|
if ( mpCurPane != NULL )
|
|
{
|
|
if ( mpSrcPane->mProps.mExactDockPredictionOn )
|
|
{
|
|
mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane, FALSE );
|
|
|
|
mpLayout->GetUpdatesManager().OnFinishChanges();
|
|
mpLayout->GetUpdatesManager().UpdateNow();
|
|
}
|
|
else
|
|
{
|
|
if (mpDraggedBar->mState == wxCBAR_FLOATING)
|
|
{
|
|
mpLayout->SetBarState( mpDraggedBar, wxCBAR_DOCKED_HORIZONTALLY, TRUE);
|
|
}
|
|
|
|
mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mpDraggedBar->mState != wxCBAR_FLOATING)
|
|
{
|
|
mpLayout->SetBarState(mpDraggedBar, wxCBAR_FLOATING, true);
|
|
}
|
|
|
|
mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ] = mHintRect;
|
|
mpLayout->ApplyBarProperties( mpDraggedBar );
|
|
}
|
|
}
|
|
|
|
mHintRect.width = -1;
|
|
|
|
// In Windows, at least, the frame needs to have a null cursor
|
|
// else child windows (such as text windows) inherit the cursor
|
|
#if 1
|
|
mpLayout->GetParentFrame().SetCursor( wxNullCursor );
|
|
#else
|
|
mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
|
|
#endif
|
|
|
|
mpLayout->ReleaseEventsFromPane( event.mpPane );
|
|
mpLayout->ReleaseEventsFromPlugin( this );
|
|
|
|
mBarDragStarted = FALSE;
|
|
|
|
if ( mBarWasFloating && mpDraggedBar->mState != wxCBAR_FLOATING )
|
|
{
|
|
// save bar's floating position before it was docked
|
|
|
|
mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ] = mFloatedBarBounds;
|
|
}
|
|
}
|
|
else
|
|
event.Skip(); // pass event to the next plugin
|
|
}
|
|
|
|
void cbBarDragPlugin::OnLDblClick( cbLeftDClickEvent& event )
|
|
{
|
|
int avoidCompilerWarning = 1;
|
|
if ( avoidCompilerWarning )
|
|
{
|
|
cbBarInfo* pHittedBar;
|
|
cbRowInfo* pRow;
|
|
|
|
if ( event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes
|
|
&pRow,
|
|
&pHittedBar ) == CB_BAR_CONTENT_HITTED
|
|
)
|
|
{
|
|
mpLayout->SetBarState( pHittedBar, wxCBAR_FLOATING, TRUE );
|
|
|
|
mpLayout->RepositionFloatedBar( pHittedBar );
|
|
|
|
return; // event is "eaten" by this plugin
|
|
}
|
|
|
|
mBarDragStarted = FALSE;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
//wxMessageBox("Hi, dblclick arrived!");
|
|
}
|
|
|
|
void cbBarDragPlugin::OnStartBarDragging( cbStartBarDraggingEvent& event )
|
|
{
|
|
mpDraggedBar = event.mpBar;
|
|
mpSrcPane = event.mpPane;
|
|
|
|
mpLayout->CaptureEventsForPane( event.mpPane );
|
|
mpLayout->CaptureEventsForPlugin( this );
|
|
|
|
mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
|
|
|
|
mBarDragStarted = TRUE;
|
|
|
|
wxRect inParent = mpDraggedBar->mBounds;
|
|
|
|
mBarWasFloating = mpDraggedBar->mState == wxCBAR_FLOATING;
|
|
|
|
if ( mBarWasFloating )
|
|
{
|
|
inParent = mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ];
|
|
mFloatedBarBounds = inParent;
|
|
}
|
|
else
|
|
event.mpPane->PaneToFrame( &inParent );
|
|
|
|
mHintRect.x = POS_UNDEFINED;
|
|
|
|
mHintRect.width = inParent.width;
|
|
mHintRect.height = inParent.height;
|
|
|
|
mMouseInRectX = event.mPos.x - inParent.x;
|
|
mMouseInRectY = event.mPos.y - inParent.y;
|
|
|
|
mpSrcPane = event.mpPane;
|
|
|
|
if ( mpDraggedBar->mState == wxCBAR_FLOATING )
|
|
|
|
mpCurPane = NULL;
|
|
else
|
|
mpCurPane = event.mpPane;
|
|
|
|
mPrevHintRect.x = POS_UNDEFINED;
|
|
|
|
mCanStick = FALSE; // we're not stuck into any pane now -
|
|
// there's nowhere to "stick-twice"
|
|
|
|
mBarWidthInSrcPane = mpDraggedBar->mDimInfo.mSizes[ mpDraggedBar->mState ].x;
|
|
|
|
if ( mpSrcPane->mProps.mRealTimeUpdatesOn == FALSE &&
|
|
mpSrcPane->mProps.mExactDockPredictionOn )
|
|
|
|
mpLayout->GetUpdatesManager().OnStartChanges(); // capture initial state of layout
|
|
|
|
// simulate the first mouse movement
|
|
|
|
int x = event.mPos.x, y = event.mPos.y;
|
|
|
|
mpSrcPane->FrameToPane( &x, &y );
|
|
|
|
cbMotionEvent motionEvt( wxPoint(x,y), event.mpPane );
|
|
|
|
|
|
this->OnMouseMove( motionEvt );
|
|
|
|
return; // event is "eaten" by this plugin
|
|
}
|
|
|
|
/*** on-screen hint-tracking related methods ***/
|
|
|
|
void cbBarDragPlugin::OnDrawHintRect( cbDrawHintRectEvent& event )
|
|
{
|
|
if ( !mpScrDc ) StartTracking();
|
|
|
|
DoDrawHintRect( event.mRect, event.mIsInClient );
|
|
|
|
if ( event.mLastTime )
|
|
|
|
FinishTracking();
|
|
}
|
|
|
|
#define _IMG_A 0xAA // Note: modified from _A to _IMG_A, _A was already defined (cygwin)
|
|
#define _IMG_B 0x00 // Note: modified from _B to _IMG_A, _B was already defined (cygwin)
|
|
#define _IMG_C 0x55 // Note: modified from _C to _IMG_C, for consistency reasons.
|
|
#define _IMG_D 0x00 // Note: modified from _D to _IMG_D, for consistency reasons.
|
|
|
|
// FOR NOW:: static
|
|
|
|
static const unsigned char _gCheckerImg[16] = { _IMG_A,_IMG_B,_IMG_C,_IMG_D,
|
|
_IMG_A,_IMG_B,_IMG_C,_IMG_D,
|
|
_IMG_A,_IMG_B,_IMG_C,_IMG_D,
|
|
_IMG_A,_IMG_B,_IMG_C,_IMG_D
|
|
};
|
|
|
|
void cbBarDragPlugin::StartTracking()
|
|
{
|
|
mpScrDc = new wxScreenDC;
|
|
|
|
wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame());
|
|
}
|
|
|
|
void cbBarDragPlugin::DoDrawHintRect( wxRect& rect, bool isInClientRect)
|
|
{
|
|
wxRect scrRect;
|
|
|
|
RectToScr( rect, scrRect );
|
|
|
|
int prevLF = mpScrDc->GetLogicalFunction();
|
|
|
|
mpScrDc->SetLogicalFunction( wxINVERT );
|
|
|
|
if ( isInClientRect )
|
|
{
|
|
// BUG BUG BUG (wx):: somehow stippled brush works only
|
|
// when the bitmap created on stack, not
|
|
// as a member of the class
|
|
|
|
wxBitmap checker( (const char*)_gCheckerImg, 8,8 );
|
|
|
|
wxBrush checkerBrush( checker );
|
|
|
|
mpScrDc->SetPen( mpLayout->mNullPen );
|
|
mpScrDc->SetBrush( checkerBrush );
|
|
|
|
int half = mInClientHintBorder / 2;
|
|
|
|
mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y - half,
|
|
scrRect.width + 2*half, mInClientHintBorder );
|
|
|
|
mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + scrRect.height - half,
|
|
scrRect.width + 2*half, mInClientHintBorder );
|
|
|
|
mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + half - 1,
|
|
mInClientHintBorder, scrRect.height - 2*half + 2);
|
|
|
|
mpScrDc->DrawRectangle( scrRect.x + scrRect.width - half,
|
|
scrRect.y + half - 1,
|
|
mInClientHintBorder, scrRect.height - 2*half + 2);
|
|
|
|
mpScrDc->SetBrush( wxNullBrush );
|
|
}
|
|
else
|
|
{
|
|
mpScrDc->SetPen( mpLayout->mBlackPen );
|
|
|
|
mpScrDc->DrawLine( scrRect.x, scrRect.y,
|
|
scrRect.x + scrRect.width, scrRect.y );
|
|
|
|
mpScrDc->DrawLine( scrRect.x, scrRect.y + 1,
|
|
scrRect.x, scrRect.y + scrRect.height );
|
|
|
|
mpScrDc->DrawLine( scrRect.x+1, scrRect.y + scrRect.height,
|
|
scrRect.x + scrRect.width, scrRect.y + scrRect.height );
|
|
|
|
mpScrDc->DrawLine( scrRect.x + scrRect.width , scrRect.y,
|
|
scrRect.x + scrRect.width, scrRect.y + scrRect.height + 1);
|
|
}
|
|
|
|
mpScrDc->SetLogicalFunction( prevLF );
|
|
}
|
|
|
|
void cbBarDragPlugin::DrawHintRect ( wxRect& rect, bool isInClientRect)
|
|
{
|
|
DoDrawHintRect( rect, isInClientRect );
|
|
}
|
|
|
|
void cbBarDragPlugin::EraseHintRect( wxRect& rect, bool isInClientRect)
|
|
{
|
|
DoDrawHintRect( rect, isInClientRect );
|
|
}
|
|
|
|
void cbBarDragPlugin::FinishTracking()
|
|
{
|
|
wxScreenDC::EndDrawingOnTop();
|
|
|
|
delete mpScrDc;
|
|
|
|
mpScrDc = NULL;
|
|
}
|
|
|
|
void cbBarDragPlugin::RectToScr( wxRect& frameRect, wxRect& scrRect )
|
|
{
|
|
scrRect = frameRect;
|
|
|
|
int x = frameRect.x, y = frameRect.y;
|
|
|
|
mpLayout->GetParentFrame().ClientToScreen( &x, &y );
|
|
|
|
scrRect.x = x;
|
|
scrRect.y = y;
|
|
}
|
|
|