diff --git a/mozilla/cmd/macfe/central/divview.cp b/mozilla/cmd/macfe/central/divview.cp index 8eb1d3cc76b..3319fd97693 100644 --- a/mozilla/cmd/macfe/central/divview.cp +++ b/mozilla/cmd/macfe/central/divview.cp @@ -17,6 +17,7 @@ */ #include "divview.h" +#include "CDividerGrippyPane.h" #include "resgui.h" #include "macutil.h" @@ -30,13 +31,14 @@ LDividedView::LDividedView( LStream* inStream ) //----------------------------------- : LView( inStream ) -, fFirstView(nil) -, fSecondView(nil) -, mCollapseFirstByDragging(false) -, mCollapseSecondByDragging(false) +, mFirstPane(nil) +, mSecondPane(nil) +, mFeatureFlags(eNoFeatures) , mDividerPosBeforeCollapsing(100) { - *inStream >> mFirstSubview >> mSecondSubview; + sSettingUp = true; + + *inStream >> mFirstSubviewID >> mSecondSubviewID; *inStream >> mDivSize; *inStream >> mFirstIndent; @@ -50,7 +52,9 @@ LDividedView::LDividedView( LStream* inStream ) *inStream >> mSlidesHorizontally; } -//----------------------------------- +Boolean LDividedView::sSettingUp; + +//---------------------------------------------------------------------------------------- LDividedView::~LDividedView() //----------------------------------- { @@ -62,168 +66,347 @@ void LDividedView::FinishCreateSelf() { LView::FinishCreateSelf(); - fFirstView = (LView*)this->FindPaneByID( mFirstSubview ); - fSecondView = (LView*)this->FindPaneByID( mSecondSubview ); - LBroadcaster* zapButton = dynamic_cast(GetZapButton()); + mFirstPane = FindPaneByID( mFirstSubviewID ); + mSecondPane = FindPaneByID( mSecondSubviewID ); + LPane* zapPane = GetZapButton(); + LBroadcaster* zapButton = dynamic_cast(zapPane); if (zapButton) { zapButton->AddListener(this); - // Make sure the first pane can be collapsed - Boolean collapseFirst, collapseSecond; - GetCollapseByDragging(collapseFirst, collapseSecond); - SetCollapseByDragging(true, collapseSecond); + // Turn off any bindings. We do this ourselves + SBooleanRect zapFrameBinding; + zapPane->GetFrameBinding(zapFrameBinding); + // NOTE THE FOLLOWING CONVENTION: THE TOP AND BOTTOM BINDINGS ARE USED + // TO SET THE FEATURE FLAGS. THEN WE TURN OFF THE POWERPLANT BINDINGS. + // This is because the entire button has to be moved, not just the + // bottom or top edge of it. So we take over this different type of + // binding ourselves. + // By the way, we cannot call SetFeatureFlags here, because we don't + // want the side-effect of positioning the zap button - we haven't + // calculated the offset yet! + if (zapFrameBinding.top) + SetFeatureFlagBits(eBindZapButtonTopOrLeft); + else if (zapFrameBinding.bottom) + SetFeatureFlagBits(eBindZapButtonBottomOrRight); + zapFrameBinding.left + = zapFrameBinding.top + = zapFrameBinding.left + = zapFrameBinding.bottom + = zapFrameBinding.right + = false; + zapPane->SetFrameBinding(zapFrameBinding); + OrientZapButtonTriangles(); } - this->SyncFrameBindings(); - mDividerPosBeforeCollapsing = GetDividerPosition(); -} + SyncFrameBindings(); + if (!IsFirstPaneCollapsed() && !IsSecondPaneCollapsed()) + mDividerPosBeforeCollapsing = GetDividerPosition(); + sSettingUp = false; +} // LDividedView::FinishCreateSelf -//----------------------------------- +//---------------------------------------------------------------------------------------- LPane* LDividedView::GetZapButton() //----------------------------------- { return FindPaneByID('Zap!'); } -//----------------------------------- -void LDividedView::ToggleFirstPane() -//----------------------------------- +//---------------------------------------------------------------------------------------- +void LDividedView::DoZapAction() +// If one pane is collapsed, restore it to the saved position. +// Otherwise, zap it as specified by the feature flags. +//---------------------------------------------------------------------------------------- { + if ((mFeatureFlags & eZapClosesFirst) && (mFeatureFlags & eZapClosesSecond)) + { + Assert_(false); // you shouldn't have set both! + UnsetFeatureFlags(eZapClosesFirst); + } Int16 delta; if (IsFirstPaneCollapsed()) delta = 1; // at left, restore to center. else if (IsSecondPaneCollapsed()) delta = -1; // at right, restore to center - else - delta = - GetDividerPosition(); // collapse left - StValueChanger save(mCollapseFirstByDragging, true); - ChangeDividerPosition(delta); -} + else if (mFeatureFlags & eZapClosesFirst) + delta = - 16000; // collapse left + else if (mFeatureFlags & eZapClosesSecond) + { + delta = 16000; // collapse second + } + FeatureFlags savedFlags = mFeatureFlags; + try + { + SetFeatureFlagBits(eCollapseBothWaysByDragging); + ChangeDividerPosition(delta); + } + catch(...) + { + } + mFeatureFlags = savedFlags; +} // LDividedView::DoZapAction -//----------------------------------- +//---------------------------------------------------------------------------------------- void LDividedView::ListenToMessage(MessageT inMessage, void* /*ioParam*/) //----------------------------------- { if (inMessage == 'Zap!') - ToggleFirstPane(); -} + DoZapAction(); +} // LDividedView::ListenToMessage -//----------------------------------- +//---------------------------------------------------------------------------------------- +void LDividedView::OnlySetFeatureFlags(FeatureFlags inFlags) +//---------------------------------------------------------------------------------------- +{ + // Since this is a public function, we don't allow it to change private bits (eg, + // the binding bits). + Assert_(inFlags == (inFlags & ~ePrivateMask)); + mFeatureFlags = (FeatureFlags)(mFeatureFlags | (inFlags & ~ePrivateMask)); + OrientZapButtonTriangles(); +} // LDividedView::OnlySetFeatureFlags + +//---------------------------------------------------------------------------------------- void LDividedView::SyncFrameBindings() -//----------------------------------- +//---------------------------------------------------------------------------------------- { SBooleanRect firstBindings; SBooleanRect secondBindings; - firstBindings.top = firstBindings.bottom = firstBindings.left = firstBindings.right = TRUE; - secondBindings.top = secondBindings.bottom = secondBindings.left = secondBindings.right = TRUE; + firstBindings.top = firstBindings.bottom = + firstBindings.left = firstBindings.right = true; + secondBindings.top = secondBindings.bottom = + secondBindings.left = secondBindings.right = true; if ( mSlidesHorizontally ) - firstBindings.right = FALSE; + { + if (IsSecondPaneCollapsed()) + secondBindings.left = false; + else + firstBindings.right = false; + } else - firstBindings.bottom = FALSE; + { + if (IsSecondPaneCollapsed()) + secondBindings.top = false; + else + firstBindings.bottom = false; + } - fFirstView->SetFrameBinding( firstBindings ); - fSecondView->SetFrameBinding( secondBindings ); -} + mFirstPane->SetFrameBinding( firstBindings ); + mSecondPane->SetFrameBinding( secondBindings ); +} // LDividedView::SyncFrameBindings -void LDividedView::PositionZapButton() -{ - SDimension16 zapFrameSize; - LPane* zapButton = GetZapButton(); - if (!zapButton) - return; - zapButton->GetFrameSize(zapFrameSize); - SDimension16 firstFrameSize; - fFirstView->GetFrameSize( firstFrameSize ); - if (mSlidesHorizontally) - zapButton->PlaceInSuperFrameAt( - firstFrameSize.width + mFirstIndent, - (mFrameSize.height >> 1) - (zapFrameSize.height >> 1), - FALSE ); +//---------------------------------------------------------------------------------------- +void LDividedView::SetZapFrame( + SInt16 inZapWidth, + SInt16 inDividerPosition, // relative to divided view's frame + SInt16 inDividerLength, + SInt16& ioZapLength, + SInt32& ioZapOffsetLateral, // relative to divided view's frame + SInt32& ioZapOffsetLongitudinal) // relative to divided view's frame + +// This routine is here to combine two cases : horizontal and vertical sliding. +// The cases are identical except for having to interchange "h" and "v", "width" and +// "height". The solution is to provide this routine in "latitude"/"longitude" +// coordinates. +// +// The Zap button is long and thin. "Lateral" means orthogonal to its long dimension, +// and "longitudinal" means parallel to its long dimension. +// +// Other blocks of code in this class could share code in a similar way. +//---------------------------------------------------------------------------------------- +{ + const SInt16 kPreferredZapSize = 150; + const UInt16 zapIndent = inZapWidth; + const UInt16 zapMaxSize = inDividerLength * 2 / 3; + ioZapLength = kPreferredZapSize; + if (ioZapLength > zapMaxSize) + ioZapLength = zapMaxSize; + ioZapOffsetLateral = inDividerPosition; + if (mFeatureFlags & eBindZapButtonTopOrLeft) + ioZapOffsetLongitudinal = zapIndent; + else if (mFeatureFlags & eBindZapButtonBottomOrRight) + ioZapOffsetLongitudinal = inDividerLength - ioZapLength - zapIndent; else - zapButton->PlaceInSuperFrameAt( - (mFrameSize.width >> 1) - (zapFrameSize.width >> 1), - firstFrameSize.height + mFirstIndent, - FALSE ); - -} + ioZapOffsetLongitudinal = (inDividerLength >> 1) - (ioZapLength >> 1); +} // LDividedView::SetZapFrame +//---------------------------------------------------------------------------------------- +void LDividedView::PositionZapButton() +//---------------------------------------------------------------------------------------- +{ + LPane* zapButton = GetZapButton(); + if (!zapButton || !mFirstPane || !FocusDraw()) + return; + + SDimension16 zapFrameSize; + zapButton->GetFrameSize(zapFrameSize); + + SDimension16 firstFrameSize; + mFirstPane->GetFrameSize(firstFrameSize); + + SPoint32 zapFrameLocation; + + if (mSlidesHorizontally) + { + SetZapFrame( + zapFrameSize.width, + firstFrameSize.width + mFirstIndent, + mFrameSize.height, + zapFrameSize.height, + zapFrameLocation.h, + zapFrameLocation.v); + } + else + { + SetZapFrame( + zapFrameSize.height, + firstFrameSize.height + mFirstIndent, + mFrameSize.width, + zapFrameSize.width, + zapFrameLocation.v, + zapFrameLocation.h); + } + zapButton->ResizeFrameTo(zapFrameSize.width, zapFrameSize.height, false); + zapButton->PlaceInSuperFrameAt(zapFrameLocation.h, zapFrameLocation.v, false); +} // LDividedView::PositionZapButton + +//---------------------------------------------------------------------------------------- +void LDividedView::SetSubPanes( + LPane* inFirstPane, + LPane* inSecondPane, + Int32 inDividerPos, + Boolean inRefresh) +// After a rearrangement of the hierarchy, change the two subviews and reposition them. +//---------------------------------------------------------------------------------------- +{ + mFirstPane = inFirstPane; + mSecondPane = inSecondPane; + + mFirstPane->PutInside(this); + mSecondPane->PutInside(this); + + Int32 secondFrameOffset = inDividerPos + mDivSize; + Int32 firstFrameSize = inDividerPos - mFirstIndent; + + StValueChanger setterUp(sSettingUp, true); + if ( mSlidesHorizontally ) + { + mFirstPane->ResizeFrameTo( firstFrameSize, + mFrameSize.height - (mFirstIndent * 2 ), + false ); + mSecondPane->ResizeFrameTo( mFrameSize.width - (secondFrameOffset + mSecondIndent), + mFrameSize.height - (mSecondIndent * 2), + false ); + + mFirstPane->PlaceInSuperFrameAt( mFirstIndent, mFirstIndent, false ); + mSecondPane->PlaceInSuperFrameAt(secondFrameOffset, + mSecondIndent, + false ); + } + else + { + mFirstPane->ResizeFrameTo( mFrameSize.width - ( mFirstIndent * 2 ), + firstFrameSize, + false ); + mSecondPane->ResizeFrameTo( mFrameSize.width - ( mSecondIndent * 2 ), + mFrameSize.height - (secondFrameOffset + mSecondIndent), + false ); + + mFirstPane->PlaceInSuperFrameAt( mFirstIndent, mFirstIndent, false ); + mSecondPane->PlaceInSuperFrameAt(mSecondIndent, + secondFrameOffset, + false ); + } + PositionZapButton(); + SyncFrameBindings(); + BroadcastMessage( msg_DividerChangedPosition, this ); + CBevelView::SubPanesChanged(this, inRefresh); +} // LDividedView::SetSubPanes + +//---------------------------------------------------------------------------------------- void LDividedView::PositionViews( Boolean willBeHoriz ) { if ( mSlidesHorizontally == willBeHoriz ) return; - this->FocusDraw(); + FocusDraw(); + mSlidesHorizontally = willBeHoriz; SDimension16 firstFrameSize; - fFirstView->GetFrameSize( firstFrameSize ); - if ( mSlidesHorizontally ) + mFirstPane->GetFrameSize( firstFrameSize ); + if ( !mSlidesHorizontally ) // ie, it did BEFORE { Int16 subpaneSize = ( mFrameSize.height - mDivSize ) / 2; - fFirstView->ResizeFrameTo( mFrameSize.width - ( mFirstIndent * 2 ), + mFirstPane->ResizeFrameTo( mFrameSize.width - ( mFirstIndent * 2 ), subpaneSize - mFirstIndent, FALSE ); - fSecondView->ResizeFrameTo( mFrameSize.width - ( mSecondIndent * 2 ), + mSecondPane->ResizeFrameTo( mFrameSize.width - ( mSecondIndent * 2 ), subpaneSize - mSecondIndent, FALSE ); - fFirstView->PlaceInSuperFrameAt( mFirstIndent, mFirstIndent, FALSE ); - fSecondView->PlaceInSuperFrameAt( mSecondIndent, - firstFrameSize.height + mFirstIndent + mDivSize, - FALSE ); + mFirstPane->PlaceInSuperFrameAt( + mFirstIndent, mFirstIndent, false ); + mSecondPane->PlaceInSuperFrameAt(mSecondIndent, + firstFrameSize.height + mFirstIndent + mDivSize, + false ); } else { Int16 subpaneSize = ( mFrameSize.width - mDivSize ) / 2; - fFirstView->ResizeFrameTo( subpaneSize - mFirstIndent, + mFirstPane->ResizeFrameTo( subpaneSize - mFirstIndent, mFrameSize.height - ( mFirstIndent * 2 ), FALSE ); - fSecondView->ResizeFrameTo( subpaneSize - mSecondIndent, + mSecondPane->ResizeFrameTo( subpaneSize - mSecondIndent, mFrameSize.height - ( mSecondIndent * 2), FALSE ); - fFirstView->PlaceInSuperFrameAt( mFirstIndent, mFirstIndent, FALSE ); - fSecondView->PlaceInSuperFrameAt( firstFrameSize.width + mFirstIndent + mDivSize, - mSecondIndent, - FALSE ); + mFirstPane->PlaceInSuperFrameAt( mFirstIndent, mFirstIndent, false ); + mSecondPane->PlaceInSuperFrameAt( + firstFrameSize.width + mFirstIndent + mDivSize, + mSecondIndent, + false ); } PositionZapButton(); - mSlidesHorizontally = willBeHoriz; - this->SyncFrameBindings(); + SyncFrameBindings(); BroadcastMessage( msg_DividerChangedPosition, this ); CBevelView::SubPanesChanged(this, true); - this->Refresh(); + Refresh(); } // LDividedView::PositionViews -// ¥Êset whether we are vertical or horizontal +//---------------------------------------------------------------------------------------- void LDividedView::SetSlidesHorizontally( Boolean isHoriz ) +// ¥Êset whether we are vertical or horizontal +//---------------------------------------------------------------------------------------- { if ( mSlidesHorizontally != isHoriz ) - this->PositionViews( isHoriz ); -} + PositionViews( isHoriz ); +} // LDividedView::SetSlidesHorizontally +//---------------------------------------------------------------------------------------- Int32 LDividedView::GetDividerPosition() const +//---------------------------------------------------------------------------------------- { Rect firstFrame; - GetSubpaneRect( (LView*)this, fFirstView, firstFrame ); - if ( this->GetSlidesHorizontally() ) + GetSubpaneRect( (LView*)this, mFirstPane, firstFrame ); + if ( GetSlidesHorizontally() ) return firstFrame.right; else return firstFrame.bottom; -} +} // LDividedView::GetDividerPosition +//---------------------------------------------------------------------------------------- void LDividedView::CalcRectBetweenPanes( Rect& invRect ) +//---------------------------------------------------------------------------------------- { Rect firstFrame; Rect secondFrame; - GetSubpaneRect( this, fFirstView, firstFrame ); - GetSubpaneRect( this, fSecondView, secondFrame ); + GetSubpaneRect( this, mFirstPane, firstFrame ); + GetSubpaneRect( this, mSecondPane, secondFrame ); - this->CalcLocalFrameRect( invRect ); + CalcLocalFrameRect( invRect ); if ( mSlidesHorizontally ) { @@ -235,17 +418,19 @@ void LDividedView::CalcRectBetweenPanes( Rect& invRect ) invRect.top = firstFrame.bottom; invRect.bottom = secondFrame.top; } -} +} +//---------------------------------------------------------------------------------------- void LDividedView::CalcDividerRect( Rect& outRect ) +//---------------------------------------------------------------------------------------- { Rect firstFrame; Rect secondFrame; - GetSubpaneRect( this, fFirstView, firstFrame ); - GetSubpaneRect( this, fSecondView, secondFrame ); + GetSubpaneRect( this, mFirstPane, firstFrame ); + GetSubpaneRect( this, mSecondPane, secondFrame ); - this->CalcLocalFrameRect( outRect ); + CalcLocalFrameRect( outRect ); if ( mSlidesHorizontally ) { @@ -265,16 +450,18 @@ void LDividedView::CalcDividerRect( Rect& outRect ) } } +//---------------------------------------------------------------------------------------- +void LDividedView::CalcLimitRect( Rect& lRect ) // ¥ this is somewhat hackish, but this routine calculates the limit rect // for dragging -- the hackish part is that it looks at its subviews // pane IDs to see if they begin with a 'D' and if so, assumes they // are also LDividedViews, and then does limiting based on that // Well, I fixed this by using dynamic_cast - jrm 97/10/17 -void LDividedView::CalcLimitRect( Rect& lRect ) +//---------------------------------------------------------------------------------------- { - this->CalcLocalFrameRect( lRect ); + CalcLocalFrameRect( lRect ); - LDividedView* other = dynamic_cast(fFirstView); + LDividedView* other = dynamic_cast(mFirstPane); if (other) { if ( other->GetSlidesHorizontally() == mSlidesHorizontally ) @@ -287,7 +474,7 @@ void LDividedView::CalcLimitRect( Rect& lRect ) local.v = other->GetDividerPosition(); other->LocalToPortPoint( local ); - this->PortToLocalPoint( local ); + PortToLocalPoint( local ); if ( mSlidesHorizontally ) lRect.left = local.h; @@ -296,7 +483,7 @@ void LDividedView::CalcLimitRect( Rect& lRect ) } } - other = dynamic_cast(fSecondView); + other = dynamic_cast(mSecondPane); if (other) { if ( other->GetSlidesHorizontally() == mSlidesHorizontally ) @@ -309,7 +496,7 @@ void LDividedView::CalcLimitRect( Rect& lRect ) local.v = other->GetDividerPosition(); other->LocalToPortPoint( local ); - this->PortToLocalPoint( local ); + PortToLocalPoint( local ); if ( mSlidesHorizontally ) lRect.right = local.h; @@ -320,53 +507,57 @@ void LDividedView::CalcLimitRect( Rect& lRect ) if ( mSlidesHorizontally ) { - if (!mCollapseFirstByDragging) + if (!(mFeatureFlags & eCollapseFirstByDragging)) lRect.left += mMinFirstSize; - if (!mCollapseSecondByDragging) + if (!(mFeatureFlags & eCollapseSecondByDragging)) lRect.right -= mMinSecondSize; } else { - if (!mCollapseFirstByDragging) + if (!(mFeatureFlags & eCollapseFirstByDragging)) lRect.top += mMinFirstSize; - if (!mCollapseSecondByDragging) + if (!(mFeatureFlags & eCollapseSecondByDragging)) lRect.bottom -= mMinSecondSize; } } +//---------------------------------------------------------------------------------------- void LDividedView::CalcSlopRect( Rect& sRect ) +//---------------------------------------------------------------------------------------- { LWindow* myWin; - myWin = LWindow::FetchWindowObject( this->GetMacPort() ); + myWin = LWindow::FetchWindowObject( GetMacPort() ); if ( myWin ) { myWin->CalcPortFrameRect( sRect ); sRect = PortToLocalRect( this, sRect ); } else - this->CalcLocalFrameRect( sRect ); + CalcLocalFrameRect( sRect ); // If we're allowed to drag/collapse, allow a drag beyond the frame - if (mCollapseFirstByDragging) + if ((mFeatureFlags & eCollapseFirstByDragging)) if (mSlidesHorizontally) sRect.left -= 100; else sRect.top -= 100; - else if (mCollapseSecondByDragging) + else if ((mFeatureFlags & eCollapseSecondByDragging)) if (mSlidesHorizontally) sRect.right += 100; else sRect.bottom += 100; } +//---------------------------------------------------------------------------------------- void LDividedView::ClickSelf( const SMouseDownEvent& inMouseDown ) +//---------------------------------------------------------------------------------------- { Rect frame; - this->CalcRectBetweenPanes( frame ); + CalcRectBetweenPanes( frame ); if ( PtInRect( inMouseDown.whereLocal, &frame ) ) { - this->FocusDraw(); + FocusDraw(); if (GetClickCount() > 1) { // we don't necessarily want users double-clicking to close the pane. @@ -374,64 +565,71 @@ void LDividedView::ClickSelf( const SMouseDownEvent& inMouseDown ) // ListenToMessage('Zap!', this); return; } - - // if the first pane is closed and dragging to open is turned off, + + // if either pane is closed and dragging to open is turned off, // bail before we get to the dragging code. - if ( !GetDividerPosition() && !CanExpandByDragging() ) + if ( (IsFirstPaneCollapsed() || IsSecondPaneCollapsed()) && !CanExpandByDragging() ) return; StRegion myRgn; - this->CalcDividerRect( frame ); + CalcDividerRect( frame ); ::RectRgn( myRgn, &frame ); Rect lRect, sRect; - this->CalcLimitRect( lRect ); - this->CalcSlopRect( sRect ); + CalcLimitRect( lRect ); + CalcSlopRect( sRect ); - long result = ::DragGrayRgn( myRgn, inMouseDown.whereLocal, - &lRect, &sRect, - mSlidesHorizontally ? hAxisOnly : vAxisOnly, nil ); + long result = ::DragGrayRgn( myRgn, inMouseDown.whereLocal, &lRect, &sRect, + mSlidesHorizontally ? hAxisOnly : vAxisOnly, nil ); Int16 delta = mSlidesHorizontally ? LoWord( result ) : HiWord( result ); - if ( ( result == kOutsideSlop ) || ( delta == 0 ) ) + if (result == kOutsideSlop || delta == 0) return; - this->ChangeDividerPosition( delta ); + ChangeDividerPosition( delta ); } } #define SAVE_VERSION 28 +//---------------------------------------------------------------------------------------- void LDividedView::SavePlace( LStream* inStream ) +//---------------------------------------------------------------------------------------- { WriteVersionTag( inStream, SAVE_VERSION ); *inStream << mSlidesHorizontally; - Int32 divPos = this->GetDividerPosition(); + Int32 divPos = GetDividerPosition(); *inStream << divPos; *inStream << mDividerPosBeforeCollapsing; } +//---------------------------------------------------------------------------------------- void LDividedView::RestorePlace( LStream* inStream ) +//---------------------------------------------------------------------------------------- { if ( !ReadVersionTag( inStream, SAVE_VERSION ) ) throw (OSErr)rcDBWrongVersion; - - Int32 shouldBe; - Boolean isHoriz; - *inStream >> isHoriz; - this->PositionViews( isHoriz ); - Int32 divPos = this->GetDividerPosition(); - *inStream >> shouldBe; - this->ChangeDividerPosition( shouldBe - divPos ); - *inStream >> mDividerPosBeforeCollapsing; -} + Boolean isSlidingHoriz; + *inStream >> isSlidingHoriz; -//----------------------------------- + Int32 shouldBeHere; + *inStream >> shouldBeHere; + + *inStream >> mDividerPosBeforeCollapsing; + + PositionViews( isSlidingHoriz ); + + Int32 divPos = GetDividerPosition(); + if (shouldBeHere != divPos) + ChangeDividerPosition( shouldBeHere - divPos ); +} // LDividedView::RestorePlace + +//---------------------------------------------------------------------------------------- void LDividedView::PlaySound(ResIDT id) -//----------------------------------- +//---------------------------------------------------------------------------------------- { // Play the swishing sound, if available SndListHandle soundH = @@ -444,13 +642,20 @@ void LDividedView::PlaySound(ResIDT id) } } -//----------------------------------- +//---------------------------------------------------------------------------------------- +Boolean LDividedView::PreferSounds() +//---------------------------------------------------------------------------------------- +{ + return false; // no sounds! no sounds! +} + +//---------------------------------------------------------------------------------------- void LDividedView::ChangeDividerPosition( Int16 delta ) // ¥ move the divider, resize the top/left pane, and // move the bottom/right one -//----------------------------------- +//---------------------------------------------------------------------------------------- { - Int32 dividerPos = this->GetDividerPosition(); + Int32 dividerPos = GetDividerPosition(); Int16 newPos = dividerPos + delta; Int16 frameBound // drag beyond which causes slam = mSlidesHorizontally ? mFrameSize.width : mFrameSize.height; @@ -459,11 +664,13 @@ void LDividedView::ChangeDividerPosition( Int16 delta ) Boolean showSecond = false; if (newPos > frameBound - mMinSecondSize) { - if (mCollapseSecondByDragging) + if ((mFeatureFlags & eCollapseSecondByDragging)) { if (IsSecondPaneCollapsed() && delta <= 0) { // Uncollapse from right + if (mDividerPosBeforeCollapsing >= frameBound) + mDividerPosBeforeCollapsing = frameBound / 2; delta = mDividerPosBeforeCollapsing - dividerPos; showSecond = true; } @@ -471,12 +678,12 @@ void LDividedView::ChangeDividerPosition( Int16 delta ) { // Collapse to right delta = frameBound - mDivSize - dividerPos; - fSecondView->Hide(); + mSecondPane->Hide(); if (dividerPos == 0) // user dragged from one extreme to the other showFirst = true; else mDividerPosBeforeCollapsing = dividerPos; - if (IsVisible()) + if (IsVisible() && PreferSounds()) PlayClosingSound(); } } @@ -485,11 +692,13 @@ void LDividedView::ChangeDividerPosition( Int16 delta ) } else if (newPos < mMinFirstSize) { - if (mCollapseFirstByDragging) + if ((mFeatureFlags & eCollapseFirstByDragging)) { if (IsFirstPaneCollapsed() && delta >= 0) { // Uncollapse from left + if (mDividerPosBeforeCollapsing >= frameBound) + mDividerPosBeforeCollapsing = frameBound / 2; delta = mDividerPosBeforeCollapsing - dividerPos; showFirst = true; } @@ -497,12 +706,12 @@ void LDividedView::ChangeDividerPosition( Int16 delta ) { // Collapse to left delta = - dividerPos; - fFirstView->Hide(); + mFirstPane->Hide(); if (dividerPos == frameBound - mDivSize) showSecond = true; // user dragged from one extreme to the other else mDividerPosBeforeCollapsing = dividerPos; - if (IsVisible()) + if (IsVisible() && PreferSounds()) PlayClosingSound(); } } @@ -514,61 +723,109 @@ void LDividedView::ChangeDividerPosition( Int16 delta ) else if (IsFirstPaneCollapsed() && delta >= 0) showFirst = true; - LPane* zapButton = GetZapButton(); - if ( mSlidesHorizontally ) + if (mSlidesHorizontally) { - fFirstView->ResizeFrameBy( delta, 0, FALSE ); - fSecondView->MoveBy( delta, 0, FALSE ); - fSecondView->ResizeFrameBy( -delta, 0, FALSE ); - if (zapButton) - zapButton->MoveBy(delta, 0, FALSE); + mFirstPane->ResizeFrameBy( delta, 0, false ); + mSecondPane->MoveBy( delta, 0, false ); + mSecondPane->ResizeFrameBy( -delta, 0, false ); } else { - fFirstView->ResizeFrameBy( 0, delta, FALSE ); - fSecondView->MoveBy( 0, delta, FALSE ); - fSecondView->ResizeFrameBy( 0, -delta, FALSE ); - if (zapButton) - zapButton->MoveBy(0, delta, FALSE); + mFirstPane->ResizeFrameBy( 0, delta, false ); + mSecondPane->MoveBy( 0, delta, false ); + mSecondPane->ResizeFrameBy( 0, -delta, false ); } + SyncFrameBindings(); BroadcastMessage( msg_DividerChangedPosition, this ); if (showFirst) - fFirstView->Show(); + mFirstPane->Show(); if (showSecond) - fSecondView->Show(); + mSecondPane->Show(); CBevelView::SubPanesChanged(this, false); - if ((showFirst || showSecond) && IsVisible()) + if ((showFirst || showSecond) && IsVisible() && PreferSounds()) PlayOpeningSound(); - this->Refresh(); + + PositionZapButton(); + OrientZapButtonTriangles(); + Refresh(); } // LDividedView::ChangeDividerPosition -void -LDividedView::ResizeFrameBy( +enum +{ + kTriangleRight = 10000 +, kTriangleDown +, kTriangleLeft +, kTriangleUp +}; + +//---------------------------------------------------------------------------------------- +void LDividedView::OrientZapButtonTriangles() +//---------------------------------------------------------------------------------------- +{ + // no grippies for mozilla??? not yet at least, maybe for HTML area. +#if 0 + CDividerGrippyPane* zapper = dynamic_cast(GetZapButton()); + if (!zapper) + return; + if (IsFirstPaneCollapsed() + || ((mFeatureFlags & eZapClosesSecond) && !IsSecondPaneCollapsed())) + zapper->SetTriangleIconID(mSlidesHorizontally ? kTriangleRight : kTriangleDown); + else if (IsSecondPaneCollapsed() + || ((mFeatureFlags & eZapClosesFirst) && !IsFirstPaneCollapsed())) + zapper->SetTriangleIconID(mSlidesHorizontally ? kTriangleLeft : kTriangleUp); +#endif +} // LDividedView::OrientZapButtonTriangles + +//---------------------------------------------------------------------------------------- +void LDividedView::ResizeFrameBy( Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh) +//---------------------------------------------------------------------------------------- { - // The big flaw in this class is that the situations when the two subpanes change - // have to be handled case by case. This is but another. LView::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh); - PositionZapButton(); - CBevelView::SubPanesChanged(this, inRefresh); + if (sSettingUp) + return; + + if (mFirstPane + && GetDividerPosition() > (mSlidesHorizontally ? + mFrameSize.width : mFrameSize.height) - mDivSize) + { + // Bug #309526. The divider is bound to the left/top. If the second pane is + // hidden, then it is bound to the right/bottom also. But if the second pane + // is showing, and the window is sized too small by dragging the grow box, + // then the divider can be out of view (not quite correct)! The real problem + // with this is that the scrollbar can be clipped. + // So if after the resize this situation obtains, make the following call. + // ChangeDividerPosition will notice that the divider is offscreen, + // and it will zap the second frame closed, so now the divider will stick to + // the edge. + ChangeDividerPosition(1); + } + else + { + PositionZapButton(); + CBevelView::SubPanesChanged(this, inRefresh); + } } +//---------------------------------------------------------------------------------------- void LDividedView::AdjustCursorSelf( Point inPortPt, const EventRecord& inMacEvent ) +//---------------------------------------------------------------------------------------- { Rect frame; - // if the pane is closed and drag-to-expand is turned off, bail. - if ( !GetDividerPosition() && !CanExpandByDragging() ) - return; - - this->CalcRectBetweenPanes( frame ); - this->PortToLocalPoint( inPortPt ); + CalcRectBetweenPanes( frame ); + PortToLocalPoint( inPortPt ); if ( PtInRect( inPortPt, &frame ) ) { + // if either pane is closed and dragging to open is turned off, + // bail before we get to cursor switching code + if ( (IsFirstPaneCollapsed() || IsSecondPaneCollapsed()) && !CanExpandByDragging() ) + return; + if ( mSlidesHorizontally ) ::SetCursor( *(::GetCursor( curs_HoriDrag ) ) ); else diff --git a/mozilla/cmd/macfe/central/divview.h b/mozilla/cmd/macfe/central/divview.h index 6bee7667142..383da3becf0 100644 --- a/mozilla/cmd/macfe/central/divview.h +++ b/mozilla/cmd/macfe/central/divview.h @@ -28,12 +28,41 @@ const MessageT msg_DividerChangedPosition = 'divc'; class LDividedView : public LView, - public LBroadcaster, - public LListener + public LBroadcaster, // broadcasts msg_DividerChangedPosition + public LListener // Listens to Zap button (if any) { public: enum {class_ID = 'DIVV'}; - + enum FeatureFlags + { + eNoFeatures = 0 + , eCollapseFirstByDragging = (1<<0) + , eCollapseSecondByDragging = (1<<1) + , eZapClosesFirst = (1<<2) + , eZapClosesSecond = (1<<3) + , eBindZapButtonBottomOrRight = (1<<4) // if neither of these.... + , eBindZapButtonTopOrLeft = (1<<5) // ... then we center it. + , eNoOpenByDragging = (1<<6) + // Handy combinations + , eCollapseBothWaysByDragging = + (eCollapseFirstByDragging|eCollapseSecondByDragging) + , eCollapseBothZapFirst = + (eCollapseBothWaysByDragging|eZapClosesFirst) + , eCollapseBothZapSecond = + (eCollapseBothWaysByDragging|eZapClosesSecond) + , eOnlyFirstIsCollapsible = + (eZapClosesFirst|eCollapseFirstByDragging) + , eOnlySecondIsCollapsible = + (eZapClosesSecond|eCollapseSecondByDragging) + // The bindings are set using the PP binding + // fields in the PP constructor resource: + , eBindingMask = + (eBindZapButtonBottomOrRight|eBindZapButtonTopOrLeft) + // Bits in this mask are not changeable through the public + // SetFeatureFlags calls: + , ePrivateMask = + (eBindingMask) + }; LDividedView( LStream* inStream ); virtual ~LDividedView(); @@ -42,7 +71,7 @@ public: void SetSlidesHorizontally( Boolean isHoriz ); Boolean GetSlidesHorizontally() const { return mSlidesHorizontally; }; UInt16 GetDividerSize() const { return mDivSize; } - void ToggleFirstPane(); + void DoZapAction(); virtual void ListenToMessage(MessageT inMessage, void* ioParam); @@ -58,23 +87,57 @@ public: virtual void SavePlace( LStream* inStream ); virtual void RestorePlace( LStream* inStream ); - void SetCollapseByDragging(Boolean inFirst, Boolean inSecond) - { mCollapseFirstByDragging = inFirst; mCollapseSecondByDragging = inSecond; } - void GetCollapseByDragging(Boolean& outFirst, Boolean& outSecond) - { outFirst = mCollapseFirstByDragging; outSecond = mCollapseSecondByDragging; } - + // These reposition things as necessary. But the bindings are private. + void OnlySetFeatureFlags(FeatureFlags inFlags); // adjusts positions etc. + void SetFeatureFlags(FeatureFlags inFlags) // adjusts positions etc. + { OnlySetFeatureFlags((FeatureFlags)(mFeatureFlags | inFlags)); } + void UnsetFeatureFlags(FeatureFlags inFlags) + { OnlySetFeatureFlags((FeatureFlags)(mFeatureFlags & ~inFlags)); } + Boolean IsSecondPaneCollapsed() const - { return GetDividerPosition() >= (mSlidesHorizontally ? mFrameSize.width : mFrameSize.height) - mDivSize; } + { return GetDividerPosition() >= (mSlidesHorizontally ? + mFrameSize.width : mFrameSize.height) - mDivSize; } Boolean IsFirstPaneCollapsed() const { return GetDividerPosition() <= 0; } + void SetSubPanes( + LPane* inFirstPane, + LPane* inSecondPane, + Int32 inDividerPos, + Boolean inRefresh); + void GetSubPanes( + LPane*& outFirstPane, + LPane*& outSecondPane) const + { outFirstPane = mFirstPane; outSecondPane = mSecondPane; } + Int32 GetDividerPosition() const; + // WARNING: this does not access a stored value, it is + // calculated by looking at the first subpane's current size. + // It doesn't work too well if the first subpane is nil, or + // if the first subpane has not yet been installed. + + + static Boolean PreferSounds(); static void PlayClosingSound() { PlaySound(128); } static void PlayOpeningSound() { PlaySound(129); } static void PlaySound(ResIDT id); + protected: LPane* GetZapButton(); void PositionZapButton(); - Int32 GetDividerPosition() const; + void OrientZapButtonTriangles(); + void SetZapFrame( + SInt16 inZapWidth, + SInt16 inDividerPosition, // rel. to div view's frame + SInt16 inDividerLength, + SInt16& ioZapLength, + SInt32& ioZapOffsetLateral, // rel. to div view's frame + SInt32& ioZapOffsetLongitudinal); // rel. to div view's frame + + // These two have no side-effects, and work on all bits. + void SetFeatureFlagBits(FeatureFlags inFlags) // no other effects + { mFeatureFlags = (FeatureFlags)(mFeatureFlags | inFlags); } + void UnsetFeatureFlagBits(FeatureFlags inFlags) // no other effects + { mFeatureFlags = (FeatureFlags)(mFeatureFlags & (~inFlags)); } // ¥Êthe area representing the divider rect (only when dragging) void CalcDividerRect( Rect& outRect ); @@ -92,30 +155,31 @@ protected: // ¥Êthis routine is called to invalidate the rectangle between // the two panes (which is larger than divider rect) when // the divider is moved - void CalcRectBetweenPanes( Rect& rect ); - - // ¥ allows the user to drag the closed pane to open it. - bool CanExpandByDragging ( ) const { return false; } ; + void CalcRectBetweenPanes( Rect& rect ); + // ¥ check if we're allowed to pull out a collapsed pane by dragging + virtual bool CanExpandByDragging ( ) const { return !(mFeatureFlags & eNoOpenByDragging); }; + // Data protected: - PaneIDT mFirstSubview; // pane ID of the top or left pane - PaneIDT mSecondSubview; // pane ID of the bottom or right pane + PaneIDT mFirstSubviewID; // pane ID of the top or left pane + PaneIDT mSecondSubviewID; // pane ID of the bottom or right pane UInt16 mDivSize; // Width of the divider Int16 mMinFirstSize; // mimimum size of top (or left) pane Int16 mMinSecondSize; // minimum size of bottom (or right) pane - Boolean mCollapseFirstByDragging; - Boolean mCollapseSecondByDragging; + FeatureFlags mFeatureFlags; Int16 mDividerPosBeforeCollapsing; Int16 mFirstIndent; Int16 mSecondIndent; - Boolean mSlidesHorizontally; // top/bottom or left/right configuration? + Boolean mSlidesHorizontally;// top/bottom or left/right configuration? - LPane* fFirstView; // top or left view - LPane* fSecondView; // bottom or right view + LPane* mFirstPane; // top or left view + LPane* mSecondPane; // bottom or right view + + static Boolean sSettingUp; }; \ No newline at end of file