///////////////////////////////////////////////////////////////////////////// // Name: panedrawpl.cpp // Purpose: cbPaneDrawPlugin implementation. // Author: Aleksandras Gluchovas // Modified by: // Created: 06/09/98 // RCS-ID: $Id: panedrawpl.cpp 35650 2005-09-23 12:56:45Z MR $ // Copyright: (c) Aleksandras Gluchovas // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // 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 #include #include "wx/utils.h" // import wxMin,wxMax macros #include "wx/fl/panedrawpl.h" // bitmap bits used by bar-resizing brush #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. 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 }; // FIXME:: The below code somehow doesn't work - cursors remain unchanged // Used: controlbar.cpp(1268): set_cursor_bits( _gHorizCursorImg, bits, 32, 16 ); // Used: controlbar.cpp(1272): set_cursor_bits( _gVertCursorImg, bits, 32, 16 ); /* static void set_cursor_bits( const char** img, char* bits, int width, int height ) { for( int i = 0; i != (width*height)/8; ++i ) bits[i] = 0; for( int y = 0; y != height; ++y ) { const char* row = img[0]; for( int x = 0; x != width; ++x ) { int bitNo = y*width + x; char value = ( row[x] != '.' ) ? 1 : 0; bits[ bitNo / sizeof(char) ] |= ( ( bitNo %sizeof(char) ) << value ); } ++img; } } */ /***** Implementation for class cbPaneDrawPlugin *****/ IMPLEMENT_DYNAMIC_CLASS( cbPaneDrawPlugin, cbPluginBase ) BEGIN_EVENT_TABLE( cbPaneDrawPlugin, cbPluginBase ) EVT_PL_LEFT_DOWN ( cbPaneDrawPlugin::OnLButtonDown ) EVT_PL_LEFT_UP ( cbPaneDrawPlugin::OnLButtonUp ) // EVT_PL_LEFT_DCLICK ( cbPaneDrawPlugin::OnLDblClick ) EVT_PL_RIGHT_UP ( cbPaneDrawPlugin::OnRButtonUp ) EVT_PL_MOTION ( cbPaneDrawPlugin::OnMouseMove ) EVT_PL_DRAW_PANE_BKGROUND ( cbPaneDrawPlugin::OnDrawPaneBackground ) EVT_PL_DRAW_PANE_DECOR ( cbPaneDrawPlugin::OnDrawPaneDecorations ) EVT_PL_DRAW_ROW_DECOR ( cbPaneDrawPlugin::OnDrawRowDecorations ) EVT_PL_DRAW_ROW_HANDLES ( cbPaneDrawPlugin::OnDrawRowHandles ) EVT_PL_DRAW_ROW_BKGROUND ( cbPaneDrawPlugin::OnDrawRowBackground ) EVT_PL_SIZE_BAR_WND ( cbPaneDrawPlugin::OnSizeBarWindow ) EVT_PL_DRAW_BAR_DECOR ( cbPaneDrawPlugin::OnDrawBarDecorations ) EVT_PL_DRAW_BAR_HANDLES ( cbPaneDrawPlugin::OnDrawBarHandles ) EVT_PL_START_DRAW_IN_AREA ( cbPaneDrawPlugin::OnStartDrawInArea ) EVT_PL_FINISH_DRAW_IN_AREA ( cbPaneDrawPlugin::OnFinishDrawInArea ) END_EVENT_TABLE() cbPaneDrawPlugin::cbPaneDrawPlugin(void) : mResizeStarted ( false ), mResizeCursorOn ( false ), mpDraggedBar ( NULL ), mpResizedRow ( NULL ), mRowHandleHitted ( false ), mIsUpperHandle ( false ), mBarHandleHitted ( false ), mIsLeftHandle ( false ), mBarContentHitted ( false ), mpClntDc ( NULL ), mpPane ( NULL ) {} cbPaneDrawPlugin::cbPaneDrawPlugin( wxFrameLayout* pPanel, int paneMask ) : cbPluginBase( pPanel, paneMask ), // bar-row resizing state varaibles mResizeStarted ( false ), mResizeCursorOn ( false ), mpDraggedBar ( NULL ), mpResizedRow ( NULL ), mRowHandleHitted ( false ), mIsUpperHandle ( false ), mBarHandleHitted ( false ), mIsLeftHandle ( false ), mBarContentHitted ( false ), mpClntDc ( NULL ), mpPane ( NULL ) {} cbPaneDrawPlugin::~cbPaneDrawPlugin() { // DBG:: wxASSERT( mpClntDc == NULL ); } void cbPaneDrawPlugin::DrawDraggedHandle( const wxPoint& pos, cbDockPane& pane ) { wxScreenDC dc; int ofsX = 0; int ofsY = 0; wxPoint fpos = pos; pane.PaneToFrame( &fpos.x, &fpos.y ); // short-cut int resizeHndSize = pane.mProps.mResizeHandleSize; // "Required for X to specify that // that we wish to draw on top of all windows // - and we optimise by specifying the area // for creating the overlap window." --J.S. wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame()); mpLayout->GetParentFrame().ClientToScreen( &ofsX, &ofsY ); int prevLF = dc.GetLogicalFunction(); // 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 ); dc.SetPen( mpLayout->mNullPen ); dc.SetBrush( checkerBrush ); dc.SetLogicalFunction( wxXOR ); if ( mHandleIsVertical ) { int delta = pos.x - mDragOrigin.x; if ( !pane.IsHorizontal() ) delta = pos.y - mDragOrigin.y; int realHndOfs; realHndOfs = pane.mBoundsInParent.x + pane.mLeftMargin + mHandleOfs; int newX = realHndOfs + delta; if ( newX + resizeHndSize > mHandleDragArea.x + mHandleDragArea.width ) newX = mHandleDragArea.x + mHandleDragArea.width - 1; if ( newX < mHandleDragArea.x ) newX = mHandleDragArea.x; mDraggedDelta = newX - realHndOfs; dc.DrawRectangle( newX + ofsX, mHandleDragArea.y + ofsY, resizeHndSize + 1, mHandleDragArea.height+1 ); } else { // otherwise, draw horizontal handle int delta = pos.y - mDragOrigin.y; if ( !pane.IsHorizontal() ) delta = pos.x - mDragOrigin.x; int realHndOfs; realHndOfs = pane.mBoundsInParent.y + pane.mTopMargin + mHandleOfs; int newY = realHndOfs + delta; if ( newY + resizeHndSize > mHandleDragArea.y + mHandleDragArea.height ) newY = mHandleDragArea.y + mHandleDragArea.height - 1; if ( newY < mHandleDragArea.y ) newY = mHandleDragArea.y; mDraggedDelta = newY - realHndOfs; dc.DrawRectangle( mHandleDragArea.x + ofsX, newY + ofsY, mHandleDragArea.width + 1, resizeHndSize + 1 ); } dc.SetLogicalFunction( prevLF ); // "End drawing on top (frees the window used for drawing // over the screen)" --J.S. wxScreenDC::EndDrawingOnTop(); } void cbPaneDrawPlugin::OnMouseMove( cbMotionEvent& event ) { if ( !mResizeStarted ) { // if nothing is started, do hit-tests bool prevWasRowHandle = mRowHandleHitted; mBarContentHitted = false; mBarHandleHitted = false; mRowHandleHitted = false; int testResult = event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes &mpResizedRow, &mpDraggedBar ); if ( testResult != CB_NO_ITEMS_HITTED ) { if ( testResult == CB_BAR_CONTENT_HITTED ) { // restore cursor, if non of the handles were hit if ( mResizeCursorOn ) { // remove resizing hints mpLayout->ReleaseEventsFromPane( event.mpPane ); mpLayout->ReleaseEventsFromPlugin( this ); mResizeCursorOn = false; mBarContentHitted = true; // 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 } // TBD:: fire something like "mouse-over-bar" event event.Skip(); // pass event to the next handler in the chain return; } wxCursor* pCurs; if ( testResult == CB_UPPER_ROW_HANDLE_HITTED || testResult == CB_LOWER_ROW_HANDLE_HITTED) { if ( event.mpPane->IsHorizontal() ) pCurs = mpLayout->mpVertCursor; else pCurs = mpLayout->mpHorizCursor; mRowHandleHitted = true; mIsUpperHandle = ( testResult == CB_UPPER_ROW_HANDLE_HITTED ); } else { // otherwise, if inter-bar handle was hitted if ( event.mpPane->IsHorizontal() ) pCurs = mpLayout->mpHorizCursor; else pCurs = mpLayout->mpVertCursor; mBarHandleHitted = true; mIsLeftHandle = ( testResult == CB_LEFT_BAR_HANDLE_HITTED ); } // avoid setting the same cursor twice if ( !mResizeCursorOn || prevWasRowHandle != mRowHandleHitted ) { mpLayout->GetParentFrame().SetCursor( *pCurs ); if ( !mResizeCursorOn ) { // caputre if not captured yet mpLayout->CaptureEventsForPane( event.mpPane ); mpLayout->CaptureEventsForPlugin( this ); } } mResizeCursorOn = true; // handled is being dragged now, thus event is "eaten" by this plugin return; } // end of if (HitTestBarHandles()) // restore cursor, if non of the handles were hit if ( mResizeCursorOn ) { mpLayout->ReleaseEventsFromPane( event.mpPane ); mpLayout->ReleaseEventsFromPlugin( this ); // 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 mResizeCursorOn = false; } event.Skip(); // pass event to the next plugin } // othewise series of actions, if something has already started else if ( mResizeStarted ) { // apply xor-mask twice DrawDraggedHandle( mPrevPos, *event.mpPane ); // draw handle in the new position DrawDraggedHandle( event.mPos, *event.mpPane ); mPrevPos = event.mPos; // handled is dragged, thus event is "eaten" by this plugin } else event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::OnLDblClick( cbLeftDClickEvent& event ) { if ( !mResizeCursorOn ) { cbBarInfo* pBarToFloat; if ( event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes &mpResizedRow, &pBarToFloat ) == CB_BAR_CONTENT_HITTED ) { return; } event.Skip(); } } void cbPaneDrawPlugin::OnLButtonDown( cbLeftDownEvent& event ) { wxASSERT( !mResizeStarted ); if ( mResizeCursorOn ) { mResizeStarted = true; mDragOrigin = event.mPos; // setup constraints for the dragging handle int from, till; mHandleOfs = 0; mHandleIsVertical = false; if ( mRowHandleHitted ) event.mpPane->GetRowResizeRange( mpResizedRow, &from, &till, mIsUpperHandle ); else // otherwise if bar handle was hitted event.mpPane->GetBarResizeRange( mpDraggedBar, &from, &till, mIsLeftHandle ); if ( mRowHandleHitted ) { mHandleIsVertical = ( event.mpPane->IsHorizontal() ) ? false : true; mHandleDragArea.x = 0; mHandleDragArea.width = event.mpPane->mPaneWidth; mHandleDragArea.y = from; mHandleDragArea.height = till - from; if ( mIsUpperHandle ) mHandleOfs = mpResizedRow->mRowY; else mHandleOfs = mpResizedRow->mRowY + mpResizedRow->mRowHeight - event.mpPane->mProps.mResizeHandleSize; } else { // otehrwise if bar handle dragged // cbRowInfo& rowInfo = *mpDraggedBar->mpRow; wxRect& bounds = mpDraggedBar->mBounds; mHandleIsVertical = ( event.mpPane->IsHorizontal() ) ? true : false; mHandleDragArea.x = from; mHandleDragArea.width = till - from; mHandleDragArea.y = bounds.y; mHandleDragArea.height = bounds.height; // left-side-handle mBounds if ( mIsLeftHandle ) mHandleOfs = bounds.x; else mHandleOfs = bounds.x + bounds.width - event.mpPane->mProps.mResizeHandleSize; } event.mpPane->PaneToFrame( &mHandleDragArea ); DrawDraggedHandle(mDragOrigin, *event.mpPane); mPrevPos = mDragOrigin; return; // handled is dragged, thus event is "eaten" by this plugin } else { cbBarInfo* pDraggedBar; if ( event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes &mpResizedRow, &pDraggedBar ) == CB_BAR_CONTENT_HITTED ) { int x = event.mPos.x, y = event.mPos.y; event.mpPane->PaneToFrame( &x, &y ); cbStartBarDraggingEvent dragEvt( pDraggedBar, wxPoint(x,y), event.mpPane ); mpLayout->FirePluginEvent( dragEvt ); return; // event is "eaten" by this plugin } } event.Skip(); // pass event to the next plugin in the chain } void cbPaneDrawPlugin::OnLButtonUp( cbLeftUpEvent& event ) { if ( mResizeStarted ) { DrawDraggedHandle( event.mPos, *event.mpPane ); mResizeStarted = false; mResizeCursorOn = false; mpLayout->ReleaseEventsFromPane( event.mpPane ); mpLayout->ReleaseEventsFromPlugin( this ); // 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 if ( mRowHandleHitted ) { event.mpPane->ResizeRow( mpResizedRow, mDraggedDelta, mIsUpperHandle ); } else { event.mpPane->ResizeBar( mpDraggedBar, mDraggedDelta, mIsLeftHandle ); } mpDraggedBar = NULL; mpResizedRow = NULL; // handled dragging action was finished by this mouse-up, // thus event is "eaten" by this plugin return; } event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::OnRButtonUp( cbRightUpEvent& event ) { wxPoint fpos = event.mPos; event.mpPane->PaneToFrame( &fpos.x, &fpos.y ); cbBarInfo* pDraggedBar; // user clicks inside the bar contnet, fire bar-customization event if ( event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes &mpResizedRow, &pDraggedBar ) == CB_BAR_CONTENT_HITTED ) { cbCustomizeBarEvent cbEvt( pDraggedBar, fpos, event.mpPane ); mpLayout->FirePluginEvent( cbEvt ); return; // event is "eaten" by this plugin } // otherwise fire whole-layout customization event cbCustomizeLayoutEvent csEvt( fpos ); mpLayout->FirePluginEvent( csEvt ); // event is "eaten" by this plugin } void cbPaneDrawPlugin::OnSizeBarWindow( cbSizeBarWndEvent& event ) { cbBarInfo& bar = *event.mpBar; mpPane = event.mpPane; // it's possible that a bar does not have it's own window! if ( !bar.mpBarWnd ) return; wxRect& bounds = event.mBoundsInParent; // check visibility if ( bounds.height != 0 ) { // size smaller than bounds, to leave space for shade lines // FIXME:: +/- 1s int nNewHeight = bounds.height - 2 - bar.mDimInfo.mVertGap *2; if(nNewHeight < 0) nNewHeight = 0; bar.mpBarWnd->wxWindow::SetSize( bounds.x + 1 + bar.mDimInfo.mHorizGap, bounds.y + 1 + bar.mDimInfo.mVertGap, bounds.width - 2 - bar.mDimInfo.mHorizGap*2, nNewHeight, 0 ); if ( !bar.mpBarWnd->IsShown() ) bar.mpBarWnd->Show( true ); } else // hide bar if not visible bar.mpBarWnd->Show( false ); event.Skip(); // pass event to the next plugin in the chain } void cbPaneDrawPlugin::OnDrawRowDecorations( cbDrawRowDecorEvent& event ) { DrawPaneShadeForRow( event.mpRow, *event.mpDc ); event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::DrawUpperRowHandle( cbRowInfo* pRow, wxDC& dc ) { wxRect& bounds = pRow->mBoundsInParent; if ( mpPane->IsHorizontal() ) { if ( pRow->mHasUpperHandle ) mpPane->DrawHorizHandle( dc, bounds.x, bounds.y-1, pRow->mRowWidth ); } else { if ( pRow->mHasUpperHandle ) mpPane->DrawVertHandle( dc, bounds.x-1, bounds.y, pRow->mRowWidth ); } } void cbPaneDrawPlugin::DrawLowerRowHandle( cbRowInfo* pRow, wxDC& dc ) { wxRect& bounds = pRow->mBoundsInParent; // check if iter-row handles present if ( mpPane->IsHorizontal() ) { if ( pRow->mHasLowerHandle ) mpPane->DrawHorizHandle( dc, bounds.x, bounds.y + bounds.height - mpPane->mProps.mResizeHandleSize - 1, pRow->mRowWidth ); } else { if ( pRow->mHasLowerHandle ) mpPane->DrawVertHandle( dc, bounds.x + bounds.width - mpPane->mProps.mResizeHandleSize - 1, bounds.y, pRow->mRowWidth ); } } void cbPaneDrawPlugin::OnDrawRowHandles( cbDrawRowHandlesEvent& event ) { // short-cuts cbRowInfo* pRow = event.mpRow; wxDC& dc = *event.mpDc; mpPane = event.mpPane; // draw handles of surrounding rows first if ( pRow->mpPrev && pRow->mpPrev->mHasLowerHandle ) DrawLowerRowHandle( pRow->mpPrev, dc ); if ( pRow->mpNext && pRow->mpNext->mHasUpperHandle ) DrawUpperRowHandle( pRow->mpNext, dc ); // draw handles of the given row if ( pRow->mHasUpperHandle ) DrawUpperRowHandle( pRow, dc ); if ( pRow->mHasLowerHandle ) DrawLowerRowHandle( pRow, dc ); event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::OnDrawPaneBackground ( cbDrawPaneBkGroundEvent& event ) { wxDC& dc = *event.mpDc; mpPane = event.mpPane; // FOR NOW:: hard-coded wxBrush bkBrush( mpLayout->mBorderPen.GetColour(), wxSOLID ); dc.SetBrush( bkBrush ); dc.SetPen( mpLayout->mNullPen ); wxRect& bounds = mpPane->mBoundsInParent; if ( mpPane->mTopMargin >= 1 ) dc.DrawRectangle( bounds.x, bounds.y, bounds.width+1, mpPane->mTopMargin + 1); if ( mpPane->mBottomMargin >= 1 ) dc.DrawRectangle( bounds.x, bounds.y + bounds.height - mpPane->mBottomMargin, bounds.width + 1, mpPane->mBottomMargin + 1); if ( mpPane->mLeftMargin >= 1 ) dc.DrawRectangle( bounds.x, bounds.y + mpPane->mTopMargin - 1, mpPane->mLeftMargin + 1, bounds.height - mpPane->mTopMargin - mpPane->mBottomMargin + 2); if ( mpPane->mRightMargin >= 1 ) dc.DrawRectangle( bounds.x + bounds.width - mpPane->mRightMargin, bounds.y + mpPane->mTopMargin - 1, mpPane->mRightMargin + 1, bounds.height - mpPane->mTopMargin - mpPane->mBottomMargin + 2); event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::OnDrawRowBackground ( cbDrawRowBkGroundEvent& event ) { // short-cuts cbRowInfo* pRow = event.mpRow; wxDC& dc = *event.mpDc; mpPane = event.mpPane; // get ready wxRect rowBounds = pRow->mBoundsInParent; bool isHorizontal = event.mpPane->IsHorizontal(); // int prevPos; if ( isHorizontal ) { // prevPos = rowBounds.x; // include one line above and below the row --rowBounds.y; rowBounds.height += 2; --rowBounds.x; rowBounds.width += 2; } else { // prevPos = rowBounds.y; // include one line above and below the row --rowBounds.x; rowBounds.width += 2; --rowBounds.y; rowBounds.height += 2; } //#define TEST_BK_ERASING #ifdef TEST_BK_ERASING // DBG:: wxBrush br0( wxColour(0,160,160), wxSOLID ); dc.SetBrush(br0); dc.SetPen ( mpLayout->mNullPen ); dc.DrawRectangle( rowBounds.x, rowBounds.y, rowBounds.width + 1, rowBounds.height + 1 ); #endif wxBrush bkBrush( mpLayout->mGrayPen.GetColour(), wxSOLID ); dc.SetPen ( mpLayout->mNullPen ); dc.SetBrush( bkBrush ); // fill background-recatangle of entire row area dc.DrawRectangle( rowBounds.x, rowBounds.y, rowBounds.width + 1, rowBounds.height + 1 ); dc.SetBrush( wxNullBrush ); // draw "shaded-side-bars" for each bar for( size_t i = 0; i != pRow->mBars.Count(); ++i ) { wxRect& bounds = pRow->mBars[i]->mBoundsInParent; if ( isHorizontal ) { DrawShade( 1, bounds, FL_ALIGN_LEFT, dc ); DrawShade( 1, bounds, FL_ALIGN_RIGHT, dc ); } else { DrawShade( 1, bounds, FL_ALIGN_TOP, dc ); DrawShade( 1, bounds, FL_ALIGN_BOTTOM, dc ); } } // draw extra shades to simulate "glued-bricks" effect // TBD:: reduce exessive drawing of shades, when the // row handle is present, and shades will be overr-drawn anyway DrawUpperRowShades( pRow, dc, 1 ); // outer shade if ( pRow->mpPrev ) { DrawLowerRowShades( pRow->mpPrev, dc, 1 ); // outter shade DrawLowerRowShades( pRow->mpPrev, dc, 0 ); // inner shade } DrawLowerRowShades( pRow, dc, 1 ); if ( pRow->mpNext ) { DrawUpperRowShades( pRow->mpNext, dc, 1 ); DrawUpperRowShades( pRow->mpNext, dc, 0 ); } event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::DrawUpperRowShades( cbRowInfo* pRow, wxDC& dc, int level ) { for( size_t i = 0; i != pRow->mBars.Count(); ++i ) { wxRect& bounds = pRow->mBars[i]->mBoundsInParent; if ( mpPane->IsHorizontal() ) { DrawShade( level, bounds, FL_ALIGN_TOP, dc ); if ( level == 1 ) { dc.SetPen( mpLayout->mDarkPen ); dc.DrawPoint( bounds.x - 1, bounds.y ); dc.SetPen( mpLayout->mLightPen ); dc.DrawPoint( bounds.x + bounds.width , bounds.y ); } } else { DrawShade( level, bounds, FL_ALIGN_LEFT, dc ); if ( level == 1 ) { dc.SetPen( mpLayout->mDarkPen ); dc.DrawPoint( bounds.x, bounds.y -1 ); dc.SetPen( mpLayout->mLightPen ); dc.DrawPoint( bounds.x, bounds.y + bounds.height ); } } } } void cbPaneDrawPlugin::DrawLowerRowShades( cbRowInfo* pRow, wxDC& dc, int level ) { for( size_t i = 0; i != pRow->mBars.Count(); ++i ) { wxRect& bounds = pRow->mBars[i]->mBoundsInParent; if ( mpPane->IsHorizontal() ) { DrawShade( level, bounds, FL_ALIGN_BOTTOM, dc ); if ( level == 1 ) { dc.SetPen( mpLayout->mDarkPen ); dc.DrawPoint( bounds.x - 1, bounds.y + bounds.height -1 ); dc.SetPen( mpLayout->mLightPen ); dc.DrawPoint( bounds.x + bounds.width , bounds.y + bounds.height -1 ); } } else { DrawShade( level, bounds, FL_ALIGN_RIGHT, dc ); if ( level == 1 ) { dc.SetPen( mpLayout->mDarkPen ); dc.DrawPoint( bounds.x + bounds.width - 1, bounds.y -1 ); dc.SetPen( mpLayout->mLightPen ); dc.DrawPoint( bounds.x + bounds.width - 1, bounds.y + bounds.height ); } } } } void cbPaneDrawPlugin::DrawBarInnerShadeRect( cbBarInfo* pBar, wxDC& dc ) { wxRect& bounds = pBar->mBoundsInParent; dc.SetPen( mpLayout->mDarkPen ); dc.DrawLine( bounds.x + bounds.width - 1, bounds.y, bounds.x + bounds.width - 1, bounds.y + bounds.height ); dc.DrawLine( bounds.x, bounds.y + bounds.height - 1, bounds.x + bounds.width, bounds.y + bounds.height -1 ); dc.SetPen( mpLayout->mLightPen ); dc.DrawLine( bounds.x, bounds.y, bounds.x + bounds.width - 1, bounds.y ); dc.DrawLine( bounds.x, bounds.y, bounds.x, bounds.y + bounds.height - 1 ); } void cbPaneDrawPlugin::DrawShade( int level, wxRect& rect, int alignment, wxDC& dc ) { // simulates "guled-bricks" appearence of control bars if ( ( alignment == FL_ALIGN_TOP && level == 1 ) || ( alignment == FL_ALIGN_BOTTOM && level == 0 ) || ( alignment == FL_ALIGN_LEFT && level == 1 ) || ( alignment == FL_ALIGN_RIGHT && level == 0 ) ) dc.SetPen( mpLayout->mDarkPen ); else dc.SetPen( mpLayout->mLightPen ); if ( alignment == FL_ALIGN_TOP ) { if ( level == 0 ) dc.DrawLine( rect.x, rect.y, rect.x + rect.width - 1, rect.y ); else dc.DrawLine( rect.x - 1, rect.y - 1, rect.x + rect.width + 0, rect.y - 1 ); } else if ( alignment == FL_ALIGN_BOTTOM ) { if ( level == 0 ) dc.DrawLine( rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1 ); else dc.DrawLine( rect.x - 1, rect.y + rect.height, rect.x + rect.width + 1, rect.y + rect.height ); } else if ( alignment == FL_ALIGN_LEFT ) { if ( level == 0 ) dc.DrawLine( rect.x, rect.y, rect.x, rect.y + rect.height - 1 ); else dc.DrawLine( rect.x - 1, rect.y - 1, rect.x - 1, rect.y + rect.height ); } else if ( alignment == FL_ALIGN_RIGHT ) { if ( level == 0 ) dc.DrawLine( rect.x + rect.width - 1, rect.y, rect.x + rect.width - 1, rect.y + rect.height ); else { dc.DrawLine( rect.x + rect.width, rect.y - 1, rect.x + rect.width, rect.y + rect.height + 1 ); } } } void cbPaneDrawPlugin::DrawShade1( int level, wxRect& rect, int alignment, wxDC& dc ) { // simulates "guled-bricks" appearence of control bars if ( ( alignment == FL_ALIGN_TOP && level == 1 ) || ( alignment == FL_ALIGN_BOTTOM && level == 0 ) || ( alignment == FL_ALIGN_LEFT && level == 1 ) || ( alignment == FL_ALIGN_RIGHT && level == 0 ) ) dc.SetPen( mpLayout->mDarkPen ); else dc.SetPen( mpLayout->mLightPen ); if ( alignment == FL_ALIGN_TOP ) { if ( level == 0 ) dc.DrawLine( rect.x, rect.y, rect.x + rect.width, rect.y ); else dc.DrawLine( rect.x, rect.y - 1, rect.x + rect.width, rect.y - 1 ); } else if ( alignment == FL_ALIGN_BOTTOM ) { if ( level == 0 ) dc.DrawLine( rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1 ); else dc.DrawLine( rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height ); } else if ( alignment == FL_ALIGN_LEFT ) { if ( level == 0 ) dc.DrawLine( rect.x, rect.y, rect.x, rect.y + rect.height ); else dc.DrawLine( rect.x - 1, rect.y, rect.x - 1, rect.y + rect.height ); } else if ( alignment == FL_ALIGN_RIGHT ) { if ( level == 0 ) dc.DrawLine( rect.x + rect.width - 1, rect.y, rect.x + rect.width - 1, rect.y + rect.height ); else { dc.DrawLine( rect.x + rect.width, rect.y , rect.x + rect.width, rect.y + rect.height ); } } } void cbPaneDrawPlugin::DrawPaneShade( wxDC& dc, int alignment ) { if ( !mpPane->mProps.mShow3DPaneBorderOn ) return; wxRect bounds = mpPane->mBoundsInParent; bounds.x += mpPane->mLeftMargin; bounds.y += mpPane->mTopMargin; bounds.width -= ( mpPane->mLeftMargin + mpPane->mRightMargin ); bounds.height -= ( mpPane->mTopMargin + mpPane->mBottomMargin ); DrawShade( 0, bounds, alignment, dc ); DrawShade( 1, bounds, alignment, dc ); } void cbPaneDrawPlugin::DrawPaneShadeForRow( cbRowInfo* pRow, wxDC& dc ) { if ( !mpPane->mProps.mShow3DPaneBorderOn ) return; // do not draw decoration, if pane has "vainished" if ( mpPane->mPaneWidth < 0 || mpPane->mPaneHeight < 0 ) return; wxRect bounds = pRow->mBoundsInParent; if ( mpPane->mAlignment == FL_ALIGN_TOP || mpPane->mAlignment == FL_ALIGN_BOTTOM ) { --bounds.y; bounds.height += 2; DrawShade1( 0, bounds, FL_ALIGN_LEFT, dc ); DrawShade1( 1, bounds, FL_ALIGN_LEFT, dc ); DrawShade1( 0, bounds, FL_ALIGN_RIGHT, dc ); DrawShade1( 1, bounds, FL_ALIGN_RIGHT, dc ); if ( !pRow->mpNext ) DrawPaneShade( dc, FL_ALIGN_BOTTOM ); if ( !pRow->mpPrev ) DrawPaneShade( dc, FL_ALIGN_TOP ); } else { --bounds.x; bounds.width += 2; DrawShade1( 0, bounds, FL_ALIGN_TOP, dc ); DrawShade1( 1, bounds, FL_ALIGN_TOP, dc ); DrawShade1( 0, bounds, FL_ALIGN_BOTTOM, dc ); DrawShade1( 1, bounds, FL_ALIGN_BOTTOM, dc ); if ( !pRow->mpNext ) DrawPaneShade( dc, FL_ALIGN_RIGHT ); if ( !pRow->mpPrev ) DrawPaneShade( dc, FL_ALIGN_LEFT ); } } void cbPaneDrawPlugin::OnDrawPaneDecorations( cbDrawPaneDecorEvent& event ) { wxDC& dc = *event.mpDc; cbDockPane* pPane = event.mpPane; RowArrayT& lst = pPane->GetRowList(); // FIXME:: this is a workaround for some glitches if ( lst.Count() ) { cbRowInfo* pLastRow = lst[ lst.Count() - 1 ]; pPane->PaintRowBackground( pLastRow, dc ); pPane->PaintRowDecorations( pLastRow, dc ); pPane->PaintRowHandles( pLastRow, dc ); } if ( !pPane->mProps.mShow3DPaneBorderOn ) return; // do not draw decoration, if pane is completely hidden if ( event.mpPane->mPaneWidth < 0 || event.mpPane->mPaneHeight < 0 ) return; DrawPaneShade( dc, FL_ALIGN_TOP ); DrawPaneShade( dc, FL_ALIGN_BOTTOM ); DrawPaneShade( dc, FL_ALIGN_LEFT ); DrawPaneShade( dc, FL_ALIGN_RIGHT ); event.Skip(); // pass event to the next plugin } // bar decoration/sizing handlers void cbPaneDrawPlugin::OnDrawBarDecorations( cbDrawBarDecorEvent& event ) { // cbBarInfo* pBar = event.mpBar; wxDC& dc = *event.mpDc; // draw brick borders wxRect& rect = event.mBoundsInParent; dc.SetPen( mpLayout->mLightPen ); // horiz dc.DrawLine( rect.x, rect.y, rect.x + rect.width-1, rect.y ); // vert dc.DrawLine( rect.x, rect.y, rect.x, rect.y + rect.height-1 ); dc.SetPen( mpLayout->mDarkPen ); // vert dc.DrawLine( rect.x + rect.width-1, rect.y, rect.x + rect.width-1, rect.y + rect.height-1 ); // horiz dc.DrawLine( rect.x, rect.y + rect.height-1, rect.x + rect.width, rect.y + rect.height-1 ); event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::OnDrawBarHandles( cbDrawBarHandlesEvent& event ) { // short-cuts cbBarInfo* pBar = event.mpBar; wxDC& dc = *event.mpDc; mpPane = event.mpPane; // draw handles around the bar if present if ( pBar->mHasLeftHandle || pBar->mHasRightHandle ) { wxRect& bounds = pBar->mBoundsInParent; if ( mpPane->IsHorizontal() ) { if ( pBar->mHasLeftHandle ) mpPane->DrawVertHandle( dc, bounds.x - mpPane->mProps.mResizeHandleSize -1, bounds.y, bounds.height ); if ( pBar->mHasRightHandle ) mpPane->DrawVertHandle( dc, bounds.x + bounds.width -1, bounds.y, bounds.height ); } else { if ( pBar->mHasLeftHandle ) mpPane->DrawHorizHandle( dc, bounds.x, bounds.y - mpPane->mProps.mResizeHandleSize - 1, bounds.width ); if ( pBar->mHasRightHandle ) mpPane->DrawHorizHandle( dc, bounds.x, bounds.y + bounds.height - 1, bounds.width ); } } event.Skip(); // pass event to the next plugin } void cbPaneDrawPlugin::OnStartDrawInArea( cbStartDrawInAreaEvent& event ) { // DBG:: wxASSERT( mpClntDc == NULL ); // FOR NOW:: create/destroy client-dc upon each drawing mpClntDc = new wxClientDC( &mpLayout->GetParentFrame() ); (*event.mppDc) = mpClntDc; mpClntDc->SetClippingRegion( event.mArea.x, event.mArea.y, event.mArea.width, event.mArea.height ); } void cbPaneDrawPlugin::OnFinishDrawInArea( cbFinishDrawInAreaEvent& WXUNUSED(event) ) { // DBG:: wxASSERT( mpClntDc ); delete mpClntDc; mpClntDc = NULL; }