mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
352 lines
11 KiB
C++
352 lines
11 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
|
||
#include "CExpandoDivider.h"
|
||
|
||
#include "prtypes.h"
|
||
#include "macutil.h"
|
||
#include "CDragBarDockControl.h"
|
||
|
||
#define kTwistieID 'Twst'
|
||
#define kCaptionID 'TwCp'
|
||
|
||
const Int16 kTwistiePixelDifference = 3; // difference in height (collapsed minus expanded).
|
||
|
||
//======================================
|
||
// CExpandoListener
|
||
//======================================
|
||
|
||
//-----------------------------------
|
||
void CExpandoListener::ListenToMessage(MessageT inMessage, void *ioParam)
|
||
//-----------------------------------
|
||
{
|
||
switch (inMessage)
|
||
{
|
||
case msg_TwistieMessage:
|
||
{
|
||
Int32 value = *(Int32*)ioParam;
|
||
SetExpandState((ExpandStateT)value);
|
||
break;
|
||
}
|
||
}
|
||
} // CExpandoListener::ListenToMessage
|
||
|
||
//======================================
|
||
// CExpandable
|
||
//======================================
|
||
|
||
//-----------------------------------
|
||
CExpandable::CExpandable(CExpansionData* closedState, CExpansionData* openState)
|
||
//-----------------------------------
|
||
: mExpandState(closed_state)
|
||
{
|
||
mStates[0] = closedState;
|
||
mStates[1] = openState;
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CExpandable::StoreCurrentDimensions()
|
||
//-----------------------------------
|
||
{
|
||
StoreDimensions(*(mStates[GetExpandState()]));
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CExpandable::RecallCurrentDimensions()
|
||
//-----------------------------------
|
||
{
|
||
RecallDimensions(*(mStates[GetExpandState()]));
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CExpandable::RecallOtherDimensions()
|
||
//-----------------------------------
|
||
{
|
||
RecallDimensions(*mStates[1 - GetExpandState()]);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CExpandable::ReadStatus(LStream* inStream)
|
||
//-----------------------------------
|
||
{
|
||
if (!inStream) return;
|
||
*inStream >> mExpandState;
|
||
mStates[0]->ReadStatus(inStream);
|
||
mStates[1]->ReadStatus(inStream);
|
||
// Don't do anything with them here.
|
||
} // CExpandable::ReadStatus
|
||
|
||
//-----------------------------------
|
||
void CExpandable::WriteStatus(LStream* inStream)
|
||
//-----------------------------------
|
||
{
|
||
StoreCurrentDimensions();
|
||
if (!inStream) return;
|
||
*inStream << mExpandState;
|
||
mStates[0]->WriteStatus(inStream);
|
||
mStates[1]->WriteStatus(inStream);
|
||
} // CExpandable::ReadStatus
|
||
|
||
const Int16 kDefaultTopFrameHeight = 110;
|
||
// FIXME. A preference? This value shows 5 full message lines in geneva 9.
|
||
|
||
//-----------------------------------
|
||
inline CDividerData::CDividerData()
|
||
//-----------------------------------
|
||
: mDividerPosition(kDefaultTopFrameHeight)
|
||
{
|
||
} // CDividerData::CDividerData
|
||
|
||
//-----------------------------------
|
||
void CDividerData::ReadStatus(LStream* inStream)
|
||
//-----------------------------------
|
||
{
|
||
if (!inStream) return;
|
||
*inStream >> mDividerPosition;
|
||
} // CDividerData::ReadStatus
|
||
|
||
//-----------------------------------
|
||
void CDividerData::WriteStatus(LStream* inStream)
|
||
//-----------------------------------
|
||
{
|
||
if (!inStream) return;
|
||
*inStream << mDividerPosition;
|
||
} // CDividerData::WriteStatus
|
||
|
||
//======================================
|
||
// CExpandoDivider
|
||
//======================================
|
||
|
||
//-----------------------------------
|
||
CExpandoDivider::CExpandoDivider(LStream* inStream)
|
||
//-----------------------------------
|
||
: Inherited( inStream )
|
||
, CExpandable(&mClosedData, &mOpenData)
|
||
{
|
||
} // CExpandoDivider::CExpandoDivider
|
||
|
||
//-----------------------------------
|
||
CExpandoDivider::~CExpandoDivider()
|
||
//-----------------------------------
|
||
{
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::FinishCreateSelf()
|
||
//-----------------------------------
|
||
{
|
||
Inherited::FinishCreateSelf();
|
||
mTwistie = FindPaneByID(kTwistieID);
|
||
mCaption = FindPaneByID(kCaptionID);
|
||
// CExpandable::InitializeStates();
|
||
StoreCurrentDimensions(); // get the closed state from PPOb
|
||
// Base class calls SyncFrameBinding which sets the "open" behavior. Undo this, then.
|
||
SetStickToBottom(true);
|
||
|
||
// Record the height of the status bar, so that we can preserve it on expansion.
|
||
LWindow* window = LWindow::FetchWindowObject(GetMacPort());
|
||
Rect windowRect;
|
||
window->CalcPortFrameRect(windowRect); // relative is fine
|
||
Rect expandoRect;
|
||
this->CalcPortFrameRect(expandoRect);
|
||
mDistanceFromWindowBottom = windowRect.bottom - expandoRect.bottom;
|
||
Assert_(mDistanceFromWindowBottom >= 0);
|
||
mDividerDistanceFromWindowBottom
|
||
= windowRect.bottom - (expandoRect.top + GetDividerPosition());
|
||
} // CExpandoDivider::FinishCreateSelf
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::StoreDimensions(CExpansionData& outState)
|
||
//-----------------------------------
|
||
{
|
||
((CDividerData&)outState).mDividerPosition = GetDividerPosition();
|
||
} // CExpandoDivider::StoreDimensions
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::RecallDimensions(const CExpansionData& inState)
|
||
//-----------------------------------
|
||
{
|
||
SInt32 dividerPosition = GetDividerPosition();
|
||
Int16 dividerDelta = ((CDividerData&)inState).mDividerPosition - dividerPosition;
|
||
this->ChangeDividerPosition(dividerDelta);
|
||
} // CExpandoDivider::RecallDimensions
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::SetStickToBottom(LPane* inPane, Boolean inStick)
|
||
//-----------------------------------
|
||
{
|
||
SBooleanRect bindings;
|
||
inPane->GetFrameBinding(bindings);
|
||
bindings.bottom = inStick;
|
||
inPane->SetFrameBinding(bindings);
|
||
} // CExpandoDivider::SetStickToBottom
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::SetStickToBottom(Boolean inStick)
|
||
//-----------------------------------
|
||
{
|
||
SetStickToBottom(mTwistie, inStick);
|
||
SetStickToBottom(mCaption, inStick);
|
||
SetStickToBottom(fFirstView, inStick);
|
||
SetStickToBottom(fSecondView, true);
|
||
} // CExpandoDivider::SetStickToBottom
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::ClickSelf(const SMouseDownEvent& inMouseDown)
|
||
//-----------------------------------
|
||
{
|
||
if (GetExpandState() == open_state) Inherited::ClickSelf(inMouseDown);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::AdjustCursorSelf(Point inPortPt, const EventRecord& inMacEvent)
|
||
//-----------------------------------
|
||
{
|
||
if (GetExpandState() == open_state) Inherited::AdjustCursorSelf(inPortPt, inMacEvent);
|
||
}
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::ChangeTwistiePosition(Int16 delta)
|
||
// Move the twistie and caption
|
||
//-----------------------------------
|
||
{
|
||
mTwistie->MoveBy(0, delta, FALSE);
|
||
mCaption->MoveBy(0, delta, FALSE);
|
||
} // CExpandoDivider::ChangeTwistiePosition
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::ChangeDividerPosition(Int16 delta)
|
||
//-----------------------------------
|
||
{
|
||
if (mExpandState == open_state && delta > 0)
|
||
{
|
||
// If the user drags the divider to the bottom, it should close the twistie.
|
||
Int32 dividerPos = this->GetDividerPosition();
|
||
Int32 newPos = dividerPos + delta;
|
||
Rect secondFrame;
|
||
GetSubpaneRect(this, fSecondView, secondFrame);
|
||
if (newPos > secondFrame.bottom - 50)
|
||
{
|
||
mTwistie->SetValue(closed_state);
|
||
return;
|
||
}
|
||
}
|
||
Inherited::ChangeDividerPosition(delta);
|
||
ChangeTwistiePosition(delta);
|
||
} // CExpandoDivider::ChangeDividerPosition
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::ResizeFrameBy(
|
||
Int16 inWidthDelta,
|
||
Int16 inHeightDelta,
|
||
Boolean inRefresh)
|
||
//-----------------------------------
|
||
{
|
||
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
|
||
// Unless we do this, there's no way to enforce the rule that the second pane's TOP
|
||
// sticks to the bottom when in the collapsed state.
|
||
if (mExpandState == closed_state && fFirstView && fSecondView)
|
||
{
|
||
SPoint32 loc1, loc2;
|
||
SDimension16 siz1, siz2;
|
||
fFirstView->GetFrameLocation(loc1);
|
||
fFirstView->GetFrameSize(siz1);
|
||
fSecondView->GetFrameLocation(loc2);
|
||
fSecondView->GetFrameSize(siz2);
|
||
Int32 secondViewOffset = siz1.height + loc1.v + mDivSize - loc2.v;
|
||
if (secondViewOffset)
|
||
{
|
||
fSecondView->MoveBy(0, secondViewOffset, false);
|
||
fSecondView->ResizeFrameBy(0, -secondViewOffset, false);
|
||
}
|
||
}
|
||
} // CExpandoDivider::ResizeFrameBy
|
||
|
||
//-----------------------------------
|
||
void CExpandoDivider::SetExpandState(ExpandStateT inExpanded)
|
||
//-----------------------------------
|
||
{
|
||
#if 0
|
||
// We now assume that the my view's bottom is flush with the bottom of the
|
||
// second subview.
|
||
SPoint32 locMe, loc2;
|
||
SDimension16 sizMe, siz2;
|
||
GetFrameSize(sizMe);
|
||
GetFrameLocation(locMe);
|
||
fSecondView->GetFrameLocation(loc2);
|
||
fSecondView->GetFrameSize(siz2);
|
||
Assert_(loc2.v + siz2.height == locMe.v + sizMe.height);
|
||
#endif // DEBUG
|
||
|
||
LWindow* win = LWindow::FetchWindowObject(GetMacPort());
|
||
Rect winRect;
|
||
win->CalcPortFrameRect(winRect); // relative is fine
|
||
const Int16 statusBarHeight = this->GetCorrectDistanceFromBottom();
|
||
const Int16 dividerDistanceFromBottom
|
||
= this->GetCorrectDividerDistanceFromBottom();
|
||
Rect expandoRect;
|
||
this->CalcPortFrameRect(expandoRect);
|
||
|
||
if (mExpandState != inExpanded)
|
||
StoreCurrentDimensions();
|
||
mExpandState = inExpanded;
|
||
if (inExpanded)
|
||
{
|
||
// When expanded, topview, twistie and caption do not stick to the bottom.
|
||
mCaption->Hide();
|
||
SetStickToBottom(false);
|
||
SyncFrameBindings();
|
||
|
||
|
||
// The expanded twistie is not as high as the collapsed one, and the following
|
||
// adjustment allows us to have a narrower divider bar.
|
||
ChangeTwistiePosition(- kTwistiePixelDifference);
|
||
|
||
// Now expand. The divider will pull the frame up.
|
||
RecallCurrentDimensions();
|
||
|
||
fSecondView->Show();
|
||
}
|
||
else
|
||
{
|
||
ChangeTwistiePosition(+ kTwistiePixelDifference);
|
||
fSecondView->Hide();
|
||
mCaption->Show();
|
||
RecallCurrentDimensions();
|
||
|
||
}
|
||
// The following is a kludge to fix cases where the bottom of Message view
|
||
// can disappear under the bottom of the window, or where the divider containing
|
||
// the twistie icon can be a one-inch thick grey area just over the bottom of the window.
|
||
short vertError = (winRect.bottom - statusBarHeight) - expandoRect.bottom;
|
||
if (vertError != 0)
|
||
{
|
||
this->ResizeFrameBy(0, vertError, false);
|
||
}
|
||
if (!inExpanded)
|
||
{
|
||
vertError = (winRect.bottom - (expandoRect.top + dividerDistanceFromBottom))
|
||
- this->GetDividerPosition();
|
||
if (vertError != 0)
|
||
this->ChangeDividerPosition(vertError);
|
||
// When collapsed, topview, twistie and caption stick to the bottom.
|
||
SetStickToBottom(true); //<2F><><EFBFBD> this line is not part of the kludge
|
||
}
|
||
} // CExpandoDivider::SetExpandedState
|
||
|