///////////////////////////////////////////////////////////////////////////// // Name: No names yet. // Purpose: Contrib. demo // Author: Aleksandras Gluchovas // Modified by: // Created: 09/09/98 // RCS-ID: $Id$ // Copyright: (c) Aleksandras Gluchovas // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "rowlayoutpl.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/rowlayoutpl.h" // exerimental "features" are still buggy #undef __EXPERIMENTAL /***** Implementation for class cbRowLayoutPlugin *****/ IMPLEMENT_DYNAMIC_CLASS( cbRowLayoutPlugin, cbPluginBase ) BEGIN_EVENT_TABLE( cbRowLayoutPlugin, cbPluginBase ) EVT_PL_LAYOUT_ROW ( cbRowLayoutPlugin::OnLayoutRow ) EVT_PL_LAYOUT_ROWS( cbRowLayoutPlugin::OnLayoutRows ) EVT_PL_RESIZE_ROW ( cbRowLayoutPlugin::OnResizeRow ) EVT_PL_INSERT_BAR ( cbRowLayoutPlugin::OnInsertBar ) EVT_PL_REMOVE_BAR ( cbRowLayoutPlugin::OnRemoveBar ) END_EVENT_TABLE() cbRowLayoutPlugin::cbRowLayoutPlugin(void) : mpPane( 0 ) {} cbRowLayoutPlugin::cbRowLayoutPlugin( wxFrameLayout* pPanel, int paneMask ) : cbPluginBase( pPanel, paneMask ), mpPane( 0 ) {} void cbRowLayoutPlugin::CheckIfAtTheBoundary( cbBarInfo* pTheBar, cbRowInfo& rowInfo ) { // this method handles situation, when fixed bar is inserted // into the row, where among fixed bars not-fixed ones are present. // In this case we need to check if the pBarNode appears to be inserted // chain of fixed-bars on the very right or left side of the row, // then all the white-space, such chain should be eliminated, // and the resulting chain justified to the right or the left // side of the row if ( !pTheBar->IsFixed() || rowInfo.mHasOnlyFixedBars ) return; cbBarInfo* pBar = rowInfo.mBars[ rowInfo.mBars.Count() - 1 ]; // slide fixed bars to the right on the right side relative to the pBarNode int prevX = mpPane->mPaneWidth; do { if ( !pBar->IsFixed() ) break; wxRect& bounds = pBar->mBounds; bounds.x = prevX - bounds.width; prevX = bounds.x; if ( pBar == pTheBar ) break; pBar = pBar->mpPrev; } while( 1 ); // slide fixed bars to the left on the left side relative to the pBarNode pBar = rowInfo.mBars[0]; prevX = 0; do { if ( pBar->IsFixed() ) break; wxRect& bounds = pBar->mBounds; bounds.x = prevX; prevX = bounds.x + bounds.width; if ( pBar == pTheBar ) break; pBar = pBar->mpNext; } while( 1 ); } void cbRowLayoutPlugin::ExpandNotFixedBars( cbRowInfo* pRow ) { ApplyLengthRatios( pRow ); // FIXME:: something's wrong? return; double freeSpc = (double)GetRowFreeSpace( pRow ); // calculate sum of precents double pcntSum = 0.0; size_t i = 0; for( i = 0; i != pRow->mBars.Count(); ++i ) { if ( !pRow->mBars[i]->IsFixed() ) pcntSum += pRow->mBars[i]->mLenRatio; } // setup bar lengths int curX = 0; for( i = 0; i != pRow->mBars.Count(); ++i ) { cbBarInfo& bar = *pRow->mBars[i]; if ( !bar.IsFixed() ) { bar.mLenRatio = bar.mLenRatio/(pcntSum); bar.mBounds.width = wxMax( mpPane->mProps.mMinCBarDim.x, int( freeSpc*bar.mLenRatio ) ); } bar.mBounds.x = curX; curX = bar.mBounds.x + bar.mBounds.width; } } void cbRowLayoutPlugin::AdjustLengthOfInserted( cbRowInfo* pRow, cbBarInfo* pTheBar ) { return; // pTheBar is not-fixed // FIXME:: what is this for?? #if 1 int totalLen = 0; size_t i; for( i = 0; i != pRow->mBars.Count(); ++i ) { if ( !pRow->mBars[i]->IsFixed() ) totalLen += pRow->mBars[i]->mBounds.width; } double curWidth = pTheBar->mBounds.width; if ( pRow->mBars.Count() ) pTheBar->mBounds.width = int( mpPane->mPaneWidth * (curWidth / double(totalLen)) ); #else double freeSpc = (double)GetRowFreeSpace( pRow ); double pcntSum = 0.0; size_t i; for( i = 0; i != pRow->mBars.Count(); ++i ) { if ( !pRow->mBars[i]->IsFixed() ) pcntSum += pRow->mBars[i]->mLenRatio; } // if no longer "balanced", assume that `pTheBar' was previously // removed from this row (kind of AI...) if ( pcntSum < 0.98 ) pTheBar->mBounds.width = freeSpc * (1.0 - pcntSum); #endif } void cbRowLayoutPlugin::FitBarsToRange( int from, int till, cbBarInfo* pTheBar, cbRowInfo* pRow ) { cbBarInfo* pFromBar = NULL; cbBarInfo* pTillBar = NULL; if ( pTheBar->mBounds.x > from ) { // it's range from the left pFromBar = pRow->mBars[0]; pTillBar = pTheBar; } else { pFromBar = pTheBar->mpNext; pTillBar = NULL; } // calc free space in the range cbBarInfo* pBar = pFromBar; int freeSpc = till-from; double pcntSum = 0; while( pBar != pTillBar ) { if ( pBar->IsFixed() ) freeSpc -= pBar->mBounds.width; else pcntSum += pBar->mLenRatio; pBar = pBar->mpNext; } // adjust not-fixed bar sizes in the range pBar = pFromBar; while( pBar != pTillBar ) { if ( !pBar->IsFixed() ) pBar->mBounds.width = wxMax( mpPane->mProps.mMinCBarDim.x, int( double(freeSpc) * (pBar->mLenRatio/pcntSum) ) ); pBar = pBar->mpNext; } // layout range, starting from the left-most bar pBar = pFromBar; int prevX = from; bool hasNotFixedBars = FALSE; while ( pBar != pTillBar ) { wxRect& bounds = pBar->mBounds; if ( !pBar->IsFixed() ) { hasNotFixedBars = TRUE; freeSpc -= bounds.width; } bounds.x = prevX; prevX = bounds.x + bounds.width; pBar = pBar->mpNext; } // make width adjustment for the right-most bar in the range, due to // lost precision when seting widths using f.p. length-ratios if ( hasNotFixedBars ) { if ( pTheBar->mBounds.x > from ) { if ( pTillBar->mpPrev ) { wxRect& tillBar = pTillBar->mpPrev->mBounds; //tillBar.width = bar.mBounds.x - tillBar.x; tillBar.width += freeSpc; } } else { cbBarInfo* pLast = pRow->mBars[ pRow->mBars.Count() - 1 ]; if ( pLast != pTheBar ) { pTheBar->mBounds.width += freeSpc; SlideRightSideBars( pTheBar ); } } } } void cbRowLayoutPlugin::MinimzeNotFixedBars( cbRowInfo* pRow, cbBarInfo* pBarToPreserve ) { size_t i; for( i = 0; i != pRow->mBars.Count(); ++i ) { if ( !pRow->mBars[i]->IsFixed() && pRow->mBars[i] != pBarToPreserve ) pRow->mBars[i]->mBounds.width = mpPane->mProps.mMinCBarDim.x; } } int cbRowLayoutPlugin::GetRowFreeSpace( cbRowInfo* pRow ) { int freeSpc = mpPane->mPaneWidth; size_t i; for( i = 0; i != pRow->mBars.Count(); ++i ) { // not-fixed bars variable length, thus their // dimensions are ignored if ( pRow->mBars[i]->IsFixed() ) freeSpc -= pRow->mBars[i]->mBounds.width; } return freeSpc; } void cbRowLayoutPlugin::RecalcLengthRatios( cbRowInfo* pRow ) { double freeSpc = double( GetRowFreeSpace( pRow ) ); cbBarInfo* pBar = pRow->mBars[0]; cbBarInfo* pLastNotFixed = NULL; double pcntLeft = 1.0; // (100%) #ifdef __EXPERIMENTAL int totalLen = 0; size_t i; for( i = 0; i != pRow->mBars.Count(); ++i ) { if ( !pRow->mBars[i]->IsFixed() ) totalLen += pRow->mBars[i]->mBounds.width; } #endif size_t i; for( i = 0; i != pRow->mBars.Count(); ++i ) { cbBarInfo& bar = *pRow->mBars[i]; if ( !bar.IsFixed() ) { #ifdef __EXPERIMENTAL bar.mLenRatio = double(bar.mBounds.width)/double(totalLen); #else bar.mLenRatio = double(bar.mBounds.width)/freeSpc; #endif pcntLeft -= bar.mLenRatio; pLastNotFixed = pBar; } } // attach remainder (the result of lost precision) to the // last not-fixed bar #if !defined(__EXPERIMENTAL) if ( pLastNotFixed ) pLastNotFixed->mLenRatio += pcntLeft; #endif } void cbRowLayoutPlugin::ApplyLengthRatios( cbRowInfo* pRow ) { double pcntSum = 0; // FOR NOW:: all-in-one size_t i = 0; for( i = 0; i != pRow->mBars.Count(); ++i ) { if ( !pRow->mBars[i]->IsFixed() ) pcntSum += pRow->mBars[i]->mLenRatio; } /* pBar = node_to_first_bar_node( pRow ); while( pBar ) { cbBarInfo& bar = node_to_bar( pBar ); if ( !bar.IsFixed() ) bar.mLenRatio = pcntSum / bar.mLenRatio; pBar = pBar->Next(); } */ int prevX = 0; double freeSpc = GetRowFreeSpace( pRow ); // tricky stuff (improtant!): // when not-fixed bar is removed from the row and there are // still some other not-fixed ones left in that row, then // the sum of mLenRatio's is no longer 1.0 - this is left // intintionally to handle the case when the removed bar // is returned right back to the row - so that it would retain // it's original dimensions in this row (this is kind of AI...) // // The problem is - when it's remvoed, the sum of // mLenRatio's is not in "balance", i.e. is < 1.0, // it's possible to restore balance, but instead of that // we artifically ajdust freeSpc value in a way that it would // look like total of mLetRatio's is 1.0, thus original // len. ratios are _preserved_: double unit = freeSpc / pcntSum; bool haveSquished = FALSE; for( i = 0; i != pRow->mBars.Count(); ++i ) { if ( !pRow->mBars[i]->IsFixed() ) { cbBarInfo& bar = *pRow->mBars[i]; if ( int( unit * bar.mLenRatio ) < mpPane->mProps.mMinCBarDim.x ) { haveSquished = TRUE; bar.mBounds.width = -1; // mark as "squished" pcntSum -= bar.mLenRatio; freeSpc -= mpPane->mProps.mMinCBarDim.x; } } } // for if ( haveSquished ) unit = freeSpc / pcntSum; for( i = 0; i != pRow->mBars.Count(); ++i ) { cbBarInfo& bar = *pRow->mBars[i]; bar.mBounds.x = prevX; if ( !bar.IsFixed() ) { if ( bar.mBounds.width == -1 ) bar.mBounds.width = mpPane->mProps.mMinCBarDim.x; else bar.mBounds.width = int( unit * bar.mLenRatio ); // a little bit of AI: // memorize bar's height and width, when docked in // the current orientation - by making the current // dimensions to be "preffered" ones for this docking state if ( !bar.IsFixed() ) { bar.mDimInfo.mSizes[ bar.mState ].x = bar.mBounds.width; bar.mDimInfo.mSizes[ bar.mState ].y = bar.mBounds.height; } } prevX = bar.mBounds.x + bar.mBounds.width; } } void cbRowLayoutPlugin::DetectBarHandles( cbRowInfo* pRow ) { // first pass from left to right (detect left-side handles) bool foundNotFixed = FALSE; size_t i; for( i = 0; i != pRow->mBars.Count(); ++i ) { cbBarInfo& bar = *pRow->mBars[i]; bar.mHasLeftHandle = FALSE; if ( !bar.IsFixed() ) { if ( foundNotFixed ) if ( bar.mpPrev && bar.mpPrev->IsFixed() ) bar.mHasLeftHandle = TRUE; foundNotFixed = TRUE; } } // pass from right to left (detect right-side handles) foundNotFixed = FALSE; cbBarInfo* pBar = pRow->mBars[ pRow->mBars.Count() - 1 ]; while( pBar ) { pBar->mHasRightHandle = FALSE; if ( !pBar->IsFixed() ) { if ( foundNotFixed ) if ( pBar->mpNext ) pBar->mHasRightHandle = TRUE; foundNotFixed = TRUE; } pBar = pBar->mpPrev; } } void cbRowLayoutPlugin::RelayoutNotFixedBarsAround( cbBarInfo* pTheBar, cbRowInfo* pRow ) { if ( !pTheBar->mpPrev ) { if ( !pTheBar->IsFixed() ) { // this bar the first in the row, move it's // left edge to the very left pTheBar->mBounds.width += pTheBar->mBounds.x; pTheBar->mBounds.x = 0; } } else FitBarsToRange( 0, pTheBar->mBounds.x, pTheBar, pRow ); if ( !pTheBar->mpNext ) { if ( !pTheBar->IsFixed() ) { // this bar is the last one, move it's // right edge to the very right pTheBar->mBounds.width = mpPane->mPaneWidth - pTheBar->mBounds.x; } } else FitBarsToRange( pTheBar->mBounds.x + pTheBar->mBounds.width, mpPane->mPaneWidth, pTheBar, pRow ); } void cbRowLayoutPlugin::LayoutItemsVertically( cbRowInfo& row ) { size_t i; for( i = 0; i != row.mBars.Count(); ++i ) { cbBarInfo& bar = *row.mBars[i]; bar.mBounds.y = row.mRowY; if ( !bar.IsFixed() ) // make all not-fixed bars of equal height bar.mBounds.height = row.mRowHeight; if ( row.mHasUpperHandle ) bar.mBounds.y += mpPane->mProps.mResizeHandleSize; } } int cbRowLayoutPlugin::CalcRowHeight( cbRowInfo& row ) { int maxHeight = 0; size_t i; for( i = 0; i != row.mBars.Count(); ++i ) maxHeight = wxMax( maxHeight, row.mBars[i]->mBounds.height ); return maxHeight; } void cbRowLayoutPlugin::StickRightSideBars( cbBarInfo* pToBar ) { cbBarInfo* pBar = pToBar->mpNext; cbBarInfo* pPrev = pToBar; while( pBar ) { wxRect& cur = pBar->mBounds; wxRect& prev = pPrev->mBounds; cur.x = prev.x + prev.width; pPrev = pBar; pBar = pBar->mpNext; } } void cbRowLayoutPlugin::SlideLeftSideBars( cbBarInfo* pTheBar ) { // shift left-side-bars to the left (with respect to "theBar"), // so that they would not obscured by each other cbBarInfo* pBar = pTheBar->mpPrev; cbBarInfo* pPrev = pTheBar; while( pBar ) { wxRect& cur = pBar->mBounds; wxRect& prev = pPrev->mBounds; if ( cur.x + cur.width > prev.x ) cur.x = prev.x - cur.width; pPrev = pBar; pBar = pBar->mpPrev; } } void cbRowLayoutPlugin::SlideRightSideBars( cbBarInfo* pTheBar ) { // shift right-side-bars to the right (with respect to "theBar"), // so that they would not be obscured by each other cbBarInfo* pBar = pTheBar->mpNext; cbBarInfo* pPrev = pTheBar; while( pBar ) { wxRect& cur = pBar->mBounds; wxRect& prev = pPrev->mBounds; if ( cur.x < prev.x + prev.width ) cur.x = prev.x + prev.width; pPrev = pBar; pBar = pBar->mpNext; } } void cbRowLayoutPlugin::ShiftLeftTrashold( cbBarInfo* pTheBar, cbRowInfo& row ) { wxRect& first = row.mBars[0]->mBounds; if ( first.x < 0 ) { row.mBars[0]->mBounds.x = 0; SlideRightSideBars( row.mBars[0] ); } } void cbRowLayoutPlugin::ShiftRightTrashold( cbBarInfo* pTheBar, cbRowInfo& row ) { wxRect& theBar = pTheBar->mBounds; do { cbBarInfo* pBar = pTheBar; // calculate free spece on the left side int leftFreeSpc = 0; while( pBar ) { wxRect& cur = pBar->mBounds; if ( pBar->mpPrev ) { wxRect& prev = pBar->mpPrev->mBounds; leftFreeSpc += cur.x - prev.x - prev.width; } else leftFreeSpc += cur.x; if ( cur.x < 0 ) { leftFreeSpc = 0; break; } pBar = pBar->mpPrev; } pBar = pTheBar; int rightOverflow = 0; if ( pTheBar->IsFixed() ) while( pBar ) { if ( !pBar->mpNext ) { wxRect& cur = pBar->mBounds; if ( cur.x + cur.width > mpPane->mPaneWidth ) rightOverflow = cur.x + cur.width - mpPane->mPaneWidth; } pBar = pBar->mpNext; } if ( rightOverflow > 0 ) { if ( leftFreeSpc <= 0 ) return; if ( pTheBar->mpNext ) { wxRect& next = pTheBar->mpNext->mBounds; // if there's enough space on the left, move over one half-obscured // bar from the right to the left side with respect to "theBar" if ( next.width < leftFreeSpc ) { cbBarInfo* pNext = pTheBar->mpNext; row.mBars.Remove( pNext ); row.mBars.Insert( pNext, row.mBars.Index( pTheBar ) ); next.x = theBar.x - next.width; // re-setup mpPrev/mpNext references after insertion mpPane->InitLinksForRow( &row ); // tighten things StickRightSideBars( pTheBar ); SlideLeftSideBars ( pTheBar ); continue; } } int leftShift = ( rightOverflow > leftFreeSpc ) ? leftFreeSpc : rightOverflow; theBar.x -= leftShift; StickRightSideBars( pTheBar ); SlideLeftSideBars ( pTheBar ); break; } // end of if ( rightOverflow ) else break; } while(1); } void cbRowLayoutPlugin::InsertBefore( cbBarInfo* pBeforeBar, cbBarInfo* pTheBar, cbRowInfo& row ) { if ( pBeforeBar ) row.mBars.Insert( pTheBar, row.mBars.Index( pBeforeBar ) ); else row.mBars.Add( pTheBar ); pTheBar->mpRow = &row; } void cbRowLayoutPlugin::DoInsertBar( cbBarInfo* pTheBar, cbRowInfo& row ) { wxRect& theBar = pTheBar->mBounds; /* OLD STUFF:: if ( theBar.x < 0 && !node_to_bar( pTheBar ).IsFixed() ) { // AI:: theBar.width += theBar.x; theBar.x = 0; } */ size_t i; for( i = 0; i != row.mBars.Count(); ++i ) { cbBarInfo& bar = *row.mBars[i]; wxRect& cur = bar.mBounds; // if bar hits the left edge if ( theBar.x <= cur.x ) { InsertBefore( &bar, pTheBar, row ); return; } else // if bar hits the right edge if ( theBar.x <= cur.x + cur.width ) { if ( theBar.x + theBar.width > cur.x + cur.width ) { InsertBefore( bar.mpNext, pTheBar, row ); return; } // otherwise the bar lies within the bounds of current bar int leftDist = theBar.x - cur.x; int rightDist = cur.x + cur.width - (theBar.x + theBar.width); if ( leftDist < rightDist ) InsertBefore( &bar, pTheBar, row ); else InsertBefore( bar.mpNext, pTheBar, row ); return; } } InsertBefore( NULL, pTheBar, row ); // insert at the end } // evnet handlers void cbRowLayoutPlugin::OnInsertBar( cbInsertBarEvent& event ) { cbBarInfo* pBarToInsert = event.mpBar; cbRowInfo* pIntoRow = event.mpRow; mpPane = event.mpPane; if ( !pBarToInsert->IsFixed() ) AdjustLengthOfInserted( pIntoRow, pBarToInsert ); DoInsertBar( pBarToInsert, *pIntoRow ); mpPane->InitLinksForRow( pIntoRow ); // relink "mpNext/mpPrev"s // perform relayouting of the bars after insertion // init bar location info pBarToInsert->mAlignment = event.mpPane->mAlignment; pBarToInsert->mRowNo = event.mpPane->GetRowIndex( pIntoRow ); #ifdef __EXPERIMENTAL if ( !pIntoRow->mHasOnlyFixedBars || !pBarToInsert->IsFixed() ) RecalcLengthRatios( pIntoRow ); #endif MinimzeNotFixedBars( pIntoRow, pBarToInsert ); SlideLeftSideBars ( pBarToInsert ); SlideRightSideBars( pBarToInsert ); ShiftLeftTrashold ( pBarToInsert, *pIntoRow ); ShiftRightTrashold( pBarToInsert, *pIntoRow ); mpPane->SyncRowFlags( pIntoRow ); CheckIfAtTheBoundary( pBarToInsert, *pIntoRow ); if ( event.mpPane->IsHorizontal() ) pBarToInsert->mState = wxCBAR_DOCKED_HORIZONTALLY; else pBarToInsert->mState = wxCBAR_DOCKED_VERTICALLY; if ( !pIntoRow->mHasOnlyFixedBars ) { #ifdef __EXPERIMENTAL ExpandNotFixedBars( pIntoRow ); #else RelayoutNotFixedBarsAround( pBarToInsert, pIntoRow ); RecalcLengthRatios( pIntoRow ); #endif DetectBarHandles( pIntoRow ); // do proportional resizing of not-fixed bars ApplyLengthRatios( pIntoRow ); } // adjust the bar's docking state // a little bit of AI: // memorize bar's height and width, when docked in // the current orientation - by making the current // dimensions to be "preferred" ones for this docking state if ( !pBarToInsert->IsFixed() ) { cbBarInfo& bar = *pBarToInsert; bar.mDimInfo.mSizes[ bar.mState ].x = bar.mBounds.width; bar.mDimInfo.mSizes[ bar.mState ].y = bar.mBounds.height; } } void cbRowLayoutPlugin::OnRemoveBar ( cbRemoveBarEvent& event ) { cbBarInfo* pBar = event.mpBar; mpPane = event.mpPane; cbRowInfo* pRow = pBar->mpRow; mpLayout->GetUpdatesManager().OnBarWillChange( pBar, pRow, event.mpPane ); // invalidate the whole row //pFirst->mpRowInfo->mMgrData.mPrevBounds.x = -1; pRow->mBars.Remove( pBar ); // rest bar information after removing it from the row pBar->mpRow = NULL; pBar->mHasLeftHandle = FALSE; pBar->mHasRightHandle = FALSE; mpPane->InitLinksForRow( pRow ); // relink "mpNext/mpPrev"s if ( pRow->mBars.Count() == 0 ) { // empty rows should not exist event.mpPane->GetRowList().Remove( pRow ); delete pRow; mpPane->InitLinksForRows(); } else { // force repainting of bars, in the row, from which the bar was removed // FIXME:: really needed? pRow->mBars[0]->mUMgrData.SetDirty(TRUE); // re-setup mHasOnlyFixedBars flag for the row information event.mpPane->SyncRowFlags( pRow ); DetectBarHandles( pRow ); if ( !pRow->mHasOnlyFixedBars ) ExpandNotFixedBars( pRow ); } } void cbRowLayoutPlugin::OnLayoutRow( cbLayoutRowEvent& event ) { cbRowInfo* pRow = event.mpRow; mpPane = event.mpPane; MinimzeNotFixedBars( pRow, NULL ); if ( !pRow->mHasOnlyFixedBars ) { // do proportional resizing of not-fixed bars ApplyLengthRatios( pRow ); } cbBarInfo& lastBar = *pRow->mBars[ pRow->mBars.Count() - 1 ]; cbBarInfo& firstBar = *pRow->mBars[ 0 ]; // FIXME:: Next line not used // wxRect& bounds = lastBar.mBounds; if ( lastBar.mBounds.x + lastBar.mBounds.width > mpPane->mPaneWidth ) { lastBar.mBounds.x = mpPane->mPaneWidth - lastBar.mBounds.width; // first simulate left-row-edge friction SlideLeftSideBars( &lastBar ); if ( firstBar.mBounds.x < 0 ) firstBar.mBounds.x = 0; // then left-row-edge function, though this // may cause some of the right-side bars going // out of row bounds, but left-side always // has the highest "priority" SlideRightSideBars( &firstBar ); } event.Skip(); // pass event to the next handler } void cbRowLayoutPlugin::OnLayoutRows( cbLayoutRowsEvent& event ) { mpPane = event.mpPane; int curY = 0; // FIXME:: Next line not used. // RowArrayT& arr = mpPane->GetRowList(); size_t i; for( i = 0; i != mpPane->GetRowList().Count(); ++i ) { cbRowInfo& row = *mpPane->GetRowList()[ i ]; // setup "has-handle" flags for rows, which depend on the existance // of not-fixed bars in the row if ( !row.mHasOnlyFixedBars ) { if ( mpPane->mAlignment == FL_ALIGN_TOP || mpPane->mAlignment == FL_ALIGN_LEFT ) { row.mHasLowerHandle = TRUE; row.mHasUpperHandle = FALSE; } else { row.mHasUpperHandle = TRUE; row.mHasLowerHandle = FALSE; } } else { // otherwise, rows with fixed-bars only, have no height-resizing handles row.mHasUpperHandle = FALSE; row.mHasLowerHandle = FALSE; } // setup vertical positions for items in the row row.mRowY = curY; row.mRowWidth = mpPane->mPaneWidth; row.mRowHeight = CalcRowHeight( row ); LayoutItemsVertically( row ); if ( row.mHasUpperHandle ) row.mRowHeight += mpPane->mProps.mResizeHandleSize; if ( row.mHasLowerHandle ) row.mRowHeight += mpPane->mProps.mResizeHandleSize; curY += row.mRowHeight; } event.Skip(); // pass event to the next handler - other hookeds plugin // may also add some "refinements" to the layout now } void cbRowLayoutPlugin::OnResizeRow( cbResizeRowEvent& event ) { // extract resize-event info int ofs = event.mHandleOfs; bool forUpperHandle = event.mForUpperHandle; cbRowInfo* pTheRow = event.mpRow; mpPane = event.mpPane; // FIXME:: Next line not used. //int newHeight = pTheRow->mRowHeight; int freeSpc = 0; if ( forUpperHandle ) { // calculate available free space from above, // which can be obtained by squeezing not-fixed height rows cbRowInfo* pRow = pTheRow->mpPrev; while( pRow ) { freeSpc += pRow->mRowHeight - event.mpPane->GetMinimalRowHeight( pRow ); pRow = pRow->mpPrev; } } else { // calculate available free space from below, // which can be obtained by squeezing not-fixed height rows cbRowInfo* pRow = pTheRow->mpNext; while( pRow ) { freeSpc += pRow->mRowHeight - mpPane->GetMinimalRowHeight( pRow ); pRow = pRow->mpNext; } } mpLayout->GetUpdatesManager().OnStartChanges(); int clientSize; // allow user adjusting pane vs. client-area space, for upper-handle if ( mpPane->IsHorizontal() ) clientSize = mpLayout->GetClientHeight(); else clientSize = mpLayout->GetClientWidth(); if ( forUpperHandle && ofs < -clientSize ) { int needed = -(ofs + clientSize); cbRowInfo* pRow = mpPane->GetRowList()[ 0 ]; // start squeezing rows from the top row towards bottom while( pRow != pTheRow && needed ) { // only not-fixed rows can be squeezed if ( !pRow->mHasOnlyFixedBars ) { int prevHeight = pRow->mRowHeight; int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ), prevHeight - needed ); if ( newHeight != prevHeight ) { event.mpPane->SetRowHeight( pRow, newHeight ); needed -= prevHeight - pRow->mRowHeight; } } pRow = pRow->mpNext; } } // allow user adjusting pane vs. client-area space, for lower-handle if ( !forUpperHandle && ofs > clientSize ) { int needed = ofs - clientSize; cbRowInfo* pRow = mpPane->GetRowList()[ mpPane->GetRowList().Count() - 1 ]; // start squeezing rows from the bottom towards the top row while( pRow && needed ) { // only not-fixed rows can be squeezed if ( !pRow->mHasOnlyFixedBars ) { int prevHeight = pRow->mRowHeight; int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ), prevHeight - needed ); if ( newHeight != prevHeight ) { event.mpPane->SetRowHeight( pRow, newHeight ); needed -= prevHeight - pRow->mRowHeight; } } pRow = pRow->mpPrev; } } if ( forUpperHandle ) event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + (-ofs) ); else event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + ofs ); mpLayout->RecalcLayout(FALSE); mpLayout->GetUpdatesManager().OnFinishChanges(); mpLayout->GetUpdatesManager().UpdateNow(); }