home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / central / CExpandoDivider.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  11.0 KB  |  352 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "CExpandoDivider.h"
  20.  
  21. #include "prtypes.h"
  22. #include "macutil.h"
  23. #include "CDragBarDockControl.h"
  24.  
  25. #define kTwistieID 'Twst'
  26. #define kCaptionID 'TwCp'
  27.  
  28. const Int16 kTwistiePixelDifference = 3; // difference in height (collapsed minus expanded).
  29.  
  30. //======================================
  31. // CExpandoListener
  32. //======================================
  33.  
  34. //-----------------------------------
  35. void CExpandoListener::ListenToMessage(MessageT inMessage, void *ioParam)
  36. //-----------------------------------
  37. {
  38.     switch (inMessage)
  39.     {
  40.     case msg_TwistieMessage:
  41.         {
  42.         Int32 value = *(Int32*)ioParam;
  43.         SetExpandState((ExpandStateT)value);
  44.         break;
  45.         }
  46.     }
  47. } // CExpandoListener::ListenToMessage
  48.  
  49. //======================================
  50. // CExpandable
  51. //======================================
  52.  
  53. //-----------------------------------
  54. CExpandable::CExpandable(CExpansionData* closedState, CExpansionData* openState)
  55. //-----------------------------------
  56. :    mExpandState(closed_state)
  57. {
  58.     mStates[0] = closedState;
  59.     mStates[1] = openState;
  60. }
  61.  
  62. //-----------------------------------
  63. void CExpandable::StoreCurrentDimensions()
  64. //-----------------------------------
  65. {
  66.     StoreDimensions(*(mStates[GetExpandState()]));
  67. }
  68.  
  69. //-----------------------------------
  70. void CExpandable::RecallCurrentDimensions()
  71. //-----------------------------------
  72. {
  73.     RecallDimensions(*(mStates[GetExpandState()]));
  74. }
  75.  
  76. //-----------------------------------
  77. void CExpandable::RecallOtherDimensions()
  78. //-----------------------------------
  79. {
  80.     RecallDimensions(*mStates[1 - GetExpandState()]);
  81. }
  82.  
  83. //-----------------------------------
  84. void CExpandable::ReadStatus(LStream* inStream)
  85. //-----------------------------------
  86. {
  87.     if (!inStream) return;
  88.     *inStream >> mExpandState;
  89.     mStates[0]->ReadStatus(inStream);
  90.     mStates[1]->ReadStatus(inStream);
  91.     // Don't do anything with them here.
  92. } // CExpandable::ReadStatus
  93.  
  94. //-----------------------------------
  95. void CExpandable::WriteStatus(LStream* inStream)
  96. //-----------------------------------
  97. {
  98.     StoreCurrentDimensions();
  99.     if (!inStream) return;
  100.     *inStream << mExpandState;
  101.     mStates[0]->WriteStatus(inStream);
  102.     mStates[1]->WriteStatus(inStream);
  103. } // CExpandable::ReadStatus
  104.  
  105. const Int16 kDefaultTopFrameHeight = 110;
  106.     // FIXME.  A preference?  This value shows 5 full message lines in geneva 9.
  107.  
  108. //-----------------------------------
  109. inline CDividerData::CDividerData()
  110. //-----------------------------------
  111. :    mDividerPosition(kDefaultTopFrameHeight)
  112. {
  113. } // CDividerData::CDividerData
  114.  
  115. //-----------------------------------
  116. void CDividerData::ReadStatus(LStream* inStream)
  117. //-----------------------------------
  118. {
  119.     if (!inStream) return;
  120.     *inStream >> mDividerPosition;
  121. } // CDividerData::ReadStatus
  122.  
  123. //-----------------------------------
  124. void CDividerData::WriteStatus(LStream* inStream)
  125. //-----------------------------------
  126. {
  127.     if (!inStream) return;
  128.     *inStream << mDividerPosition;
  129. } // CDividerData::WriteStatus
  130.  
  131. //======================================
  132. // CExpandoDivider
  133. //======================================
  134.  
  135. //-----------------------------------
  136. CExpandoDivider::CExpandoDivider(LStream* inStream)
  137. //-----------------------------------
  138. :    Inherited( inStream )
  139. ,    CExpandable(&mClosedData, &mOpenData)
  140. {
  141. } // CExpandoDivider::CExpandoDivider
  142.  
  143. //-----------------------------------
  144. CExpandoDivider::~CExpandoDivider()
  145. //-----------------------------------
  146. {
  147. }
  148.  
  149. //-----------------------------------
  150. void CExpandoDivider::FinishCreateSelf()
  151. //-----------------------------------
  152. {
  153.     Inherited::FinishCreateSelf();
  154.     mTwistie = FindPaneByID(kTwistieID);
  155.     mCaption = FindPaneByID(kCaptionID);
  156. //    CExpandable::InitializeStates();
  157.     StoreCurrentDimensions(); // get the closed state from PPOb
  158.     // Base class calls SyncFrameBinding which sets the "open" behavior. Undo this, then.
  159.     SetStickToBottom(true);
  160.  
  161.     // Record the height of the status bar, so that we can preserve it on expansion.
  162.     LWindow* window = LWindow::FetchWindowObject(GetMacPort());
  163.     Rect windowRect;
  164.     window->CalcPortFrameRect(windowRect); // relative is fine
  165.     Rect expandoRect;
  166.     this->CalcPortFrameRect(expandoRect);
  167.     mDistanceFromWindowBottom = windowRect.bottom - expandoRect.bottom;
  168.     Assert_(mDistanceFromWindowBottom >= 0);
  169.     mDividerDistanceFromWindowBottom
  170.         = windowRect.bottom - (expandoRect.top + GetDividerPosition());
  171. } // CExpandoDivider::FinishCreateSelf
  172.  
  173. //-----------------------------------
  174. void CExpandoDivider::StoreDimensions(CExpansionData& outState)
  175. //-----------------------------------
  176. {
  177.     ((CDividerData&)outState).mDividerPosition = GetDividerPosition();
  178. } // CExpandoDivider::StoreDimensions
  179.  
  180. //-----------------------------------
  181. void CExpandoDivider::RecallDimensions(const CExpansionData& inState)
  182. //-----------------------------------
  183. {
  184.     SInt32 dividerPosition = GetDividerPosition();
  185.     Int16 dividerDelta = ((CDividerData&)inState).mDividerPosition - dividerPosition;
  186.     this->ChangeDividerPosition(dividerDelta);
  187. } // CExpandoDivider::RecallDimensions
  188.  
  189. //-----------------------------------
  190. void CExpandoDivider::SetStickToBottom(LPane* inPane, Boolean inStick)
  191. //-----------------------------------
  192. {
  193.     SBooleanRect bindings;
  194.     inPane->GetFrameBinding(bindings);
  195.     bindings.bottom = inStick;
  196.     inPane->SetFrameBinding(bindings);
  197. } // CExpandoDivider::SetStickToBottom
  198.  
  199. //-----------------------------------
  200. void CExpandoDivider::SetStickToBottom(Boolean inStick)
  201. //-----------------------------------
  202. {
  203.     SetStickToBottom(mTwistie, inStick);
  204.     SetStickToBottom(mCaption, inStick);
  205.     SetStickToBottom(fFirstView, inStick);
  206.     SetStickToBottom(fSecondView, true);
  207. } // CExpandoDivider::SetStickToBottom
  208.  
  209. //-----------------------------------
  210. void CExpandoDivider::ClickSelf(const SMouseDownEvent& inMouseDown)
  211. //-----------------------------------
  212. {
  213.     if (GetExpandState() == open_state) Inherited::ClickSelf(inMouseDown);
  214. }
  215.  
  216. //-----------------------------------
  217. void CExpandoDivider::AdjustCursorSelf(Point inPortPt, const EventRecord& inMacEvent)
  218. //-----------------------------------
  219. {
  220.     if (GetExpandState() == open_state) Inherited::AdjustCursorSelf(inPortPt, inMacEvent);
  221. }
  222.  
  223. //-----------------------------------
  224. void CExpandoDivider::ChangeTwistiePosition(Int16 delta)
  225. // Move the twistie and caption
  226. //-----------------------------------
  227. {
  228.     mTwistie->MoveBy(0, delta, FALSE);
  229.     mCaption->MoveBy(0, delta, FALSE);
  230. } // CExpandoDivider::ChangeTwistiePosition
  231.  
  232. //-----------------------------------
  233. void CExpandoDivider::ChangeDividerPosition(Int16 delta)
  234. //-----------------------------------
  235. {
  236.     if (mExpandState == open_state && delta > 0)
  237.     {
  238.         // If the user drags the divider to the bottom, it should close the twistie.
  239.         Int32 dividerPos = this->GetDividerPosition();
  240.         Int32 newPos = dividerPos + delta;
  241.         Rect secondFrame;
  242.         GetSubpaneRect(this, fSecondView, secondFrame);
  243.         if (newPos > secondFrame.bottom - 50)
  244.         {
  245.             mTwistie->SetValue(closed_state);
  246.             return;
  247.         }
  248.     }
  249.     Inherited::ChangeDividerPosition(delta);
  250.     ChangeTwistiePosition(delta);
  251. } // CExpandoDivider::ChangeDividerPosition
  252.  
  253. //-----------------------------------
  254. void CExpandoDivider::ResizeFrameBy(
  255.     Int16        inWidthDelta,
  256.     Int16        inHeightDelta,
  257.     Boolean        inRefresh)
  258. //-----------------------------------
  259. {
  260.     Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
  261.     // Unless we do this, there's no way to enforce the rule that the second pane's TOP
  262.     // sticks to the bottom when in the collapsed state.
  263.     if (mExpandState == closed_state && fFirstView && fSecondView)
  264.     {
  265.         SPoint32 loc1, loc2;
  266.         SDimension16 siz1, siz2;
  267.         fFirstView->GetFrameLocation(loc1);
  268.         fFirstView->GetFrameSize(siz1);
  269.         fSecondView->GetFrameLocation(loc2);
  270.         fSecondView->GetFrameSize(siz2);
  271.         Int32 secondViewOffset = siz1.height + loc1.v + mDivSize - loc2.v;
  272.         if (secondViewOffset)
  273.         {
  274.             fSecondView->MoveBy(0, secondViewOffset, false);
  275.             fSecondView->ResizeFrameBy(0, -secondViewOffset, false);
  276.         }
  277.     }
  278. } // CExpandoDivider::ResizeFrameBy
  279.  
  280. //-----------------------------------
  281. void CExpandoDivider::SetExpandState(ExpandStateT inExpanded)
  282. //-----------------------------------
  283. {
  284. #if 0
  285.     // We now assume that the my view's bottom is flush with the bottom of the
  286.     // second subview.
  287.     SPoint32 locMe, loc2;
  288.     SDimension16 sizMe, siz2;
  289.     GetFrameSize(sizMe);
  290.     GetFrameLocation(locMe);
  291.     fSecondView->GetFrameLocation(loc2);
  292.     fSecondView->GetFrameSize(siz2);
  293.     Assert_(loc2.v + siz2.height == locMe.v + sizMe.height);
  294. #endif // DEBUG
  295.  
  296.     LWindow* win = LWindow::FetchWindowObject(GetMacPort());
  297.     Rect winRect;
  298.     win->CalcPortFrameRect(winRect); // relative is fine
  299.     const Int16 statusBarHeight = this->GetCorrectDistanceFromBottom();
  300.     const Int16 dividerDistanceFromBottom
  301.         = this->GetCorrectDividerDistanceFromBottom();
  302.     Rect expandoRect;
  303.     this->CalcPortFrameRect(expandoRect);
  304.  
  305.     if (mExpandState != inExpanded)
  306.         StoreCurrentDimensions();
  307.     mExpandState = inExpanded;
  308.     if (inExpanded)
  309.     {
  310.         // When expanded, topview, twistie and caption do not stick to the bottom.
  311.         mCaption->Hide();
  312.         SetStickToBottom(false);
  313.         SyncFrameBindings();
  314.         
  315.         
  316.         // The expanded twistie is not as high as the collapsed one, and the following
  317.         // adjustment allows us to have a narrower divider bar.
  318.         ChangeTwistiePosition(- kTwistiePixelDifference);
  319.         
  320.         // Now expand.  The divider will pull the frame up.
  321.         RecallCurrentDimensions();
  322.  
  323.         fSecondView->Show();
  324.     }
  325.     else
  326.     {
  327.         ChangeTwistiePosition(+ kTwistiePixelDifference);
  328.         fSecondView->Hide();
  329.         mCaption->Show();
  330.         RecallCurrentDimensions();
  331.  
  332.     }
  333.     // The following is a kludge to fix cases where the bottom of Message view
  334.     // can disappear under the bottom of the window, or where the divider containing
  335.     // the twistie icon can be a one-inch thick grey area just over the bottom of the window.
  336.     short vertError = (winRect.bottom - statusBarHeight) - expandoRect.bottom;
  337.     if (vertError != 0)
  338.     {
  339.         this->ResizeFrameBy(0, vertError, false);
  340.     }
  341.     if (!inExpanded)
  342.     {
  343.         vertError = (winRect.bottom - (expandoRect.top + dividerDistanceFromBottom))
  344.                                     - this->GetDividerPosition();
  345.         if (vertError != 0)
  346.             this->ChangeDividerPosition(vertError);
  347.         // When collapsed, topview, twistie and caption stick to the bottom.
  348.         SetStickToBottom(true); //ÑÑÑ this line is not part of the kludge
  349.     }
  350. } // CExpandoDivider::SetExpandedState
  351.  
  352.