home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / gui / CGATabBox.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  19.0 KB  |  605 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.  
  20. /*====================================================================================*/
  21.     #pragma mark INCLUDE FILES
  22. /*====================================================================================*/
  23.  
  24. #include "CGATabBox.h"
  25.  
  26. #include <LGAPushButton.h>
  27. #include <UGraphicsUtilities.h>
  28. #include <UGAColorRamp.h>
  29.  
  30.  
  31. /*====================================================================================*/
  32.     #pragma mark TYPEDEFS
  33. /*====================================================================================*/
  34.  
  35. typedef struct {
  36.     PaneIDT        tabPaneID;            // ID of the pane associated with the tab
  37.     PaneIDT        latentCommanderID;    // Last active commander ID, 0 if none
  38. } TabLatentCommanderT;
  39.  
  40.  
  41. /*====================================================================================*/
  42.     #pragma mark CONSTANTS
  43. /*====================================================================================*/
  44.  
  45. static const Int16 cSelectedTabShiftH = 2;
  46. static const Int16 cSelectedTabShiftV = 2;
  47.  
  48.  
  49. /*====================================================================================*/
  50.     #pragma mark INTERNAL CLASS DECLARATIONS
  51. /*====================================================================================*/
  52.  
  53. // CGATabBoxTab
  54.  
  55. class CGATabBoxTab : public LGAPushButton {
  56.  
  57. public:
  58.  
  59.                         enum { class_ID = 'TbBt' };
  60.                         CGATabBoxTab(LStream *inStream) :
  61.                                      LGAPushButton(inStream),
  62.                                      mSelected(false) {
  63.                         }
  64.                         
  65.     void                RefreshHiddenBottom(void);
  66.  
  67. protected:
  68.  
  69.     virtual void        DrawSelf(void);
  70.     virtual void        ClickSelf(const SMouseDownEvent &inMouseDown);
  71.     virtual void        BroadcastValueMessage(void);
  72.     
  73.     virtual void        CalcTitleRect(Rect &outRect);
  74.     virtual void        DrawButtonNormalColor(void);
  75.     
  76.     Boolean                IsSelectedTab(void) {
  77.                             return (((CGATabBox *) mSuperView)->GetCurrentTabID() == mPaneID);
  78.                         }
  79.  
  80.     // Instance variables
  81.     
  82.     Boolean                mSelected;
  83. };
  84.  
  85.  
  86.  
  87. /*====================================================================================*/
  88.     #pragma mark INTERNAL FUNCTION PROTOTYPES
  89. /*====================================================================================*/
  90.  
  91.  
  92. /*====================================================================================*/
  93.     #pragma mark CLASS IMPLEMENTATIONS
  94. /*====================================================================================*/
  95.  
  96. #pragma mark -
  97.  
  98. /*======================================================================================
  99.     Register PP classes associated with this tab box.
  100. ======================================================================================*/
  101.  
  102. void CGATabBox::RegisterTabBoxClasses(void) {
  103.  
  104.     RegisterClass_(CGATabBoxTab);
  105.     RegisterClass_(CGATabBox);
  106. }
  107.  
  108.  
  109. /*======================================================================================
  110.     Constructor.
  111. ======================================================================================*/
  112.  
  113. CGATabBox::CGATabBox(LStream *inStream) :
  114.                        LGABox_fixes(inStream),
  115.                        LListener(),
  116.                        LBroadcaster(),
  117.                        mCurrentTabID(0),
  118.                        mCurrentPaneID(0),
  119.                        mTabLatentCommanders(sizeof(TabLatentCommanderT)) {
  120.  
  121.     mHasBorder = true;
  122.     mBorderStyle = borderStyleGA_EmbossedOneBorder;
  123.     mTitlePosition = titlePositionGA_None;
  124.     mTitle[0] = 0;
  125. }
  126.  
  127.  
  128. /*======================================================================================
  129.     Set the currently selected tab.
  130. ======================================================================================*/
  131.  
  132. void CGATabBox::SetCurrentTabID(PaneIDT inTabID) {
  133.  
  134.     if ( mCurrentTabID == inTabID ) return;
  135.     Boolean updatePort = false;
  136.     
  137.     CGATabBoxTab *lastTab = nil, *newTab = nil;
  138.     LTabGroup *theTabGroup = nil;
  139.     
  140.     // Hide old view
  141.     
  142.     if ( mCurrentTabID != 0 ) {
  143.         lastTab = GetTab(mCurrentTabID);
  144.         if ( lastTab != nil ) {
  145.             TabBoxCanChangeT canChangeRec = { this, true };
  146.             BroadcastMessage(msg_TabViewCanChange, &canChangeRec);
  147.             if ( canChangeRec.canChange ) {
  148.                 if ( lastTab->GetValueMessage() != 0 ) {
  149.                     LPane *thePane = FindPaneByID(lastTab->GetValueMessage());
  150.                     if ( thePane != nil ) {
  151.                         theTabGroup = FindTabGroup();
  152.                         StoreLatentTabCommander(dynamic_cast<LView *>(thePane));
  153.                         // Switch the window to the current commander so that a tab group
  154.                         // doesn't swap commanders as they are hidden
  155.                         if ( theTabGroup != nil ) {
  156.                             LCommander::SwitchTarget(LWindow::FetchWindowObject(GetMacPort()));
  157.                         }
  158.                         thePane->Hide();
  159.                     }
  160.                 }
  161.                 lastTab->SetTextTraitsID(GetTextTraitsID() + 1);
  162.                 lastTab->RefreshHiddenBottom();
  163.             } else {
  164.                 return;    // Can't change
  165.             }
  166.         }
  167.     }
  168.     
  169.     mCurrentTabID = inTabID;
  170.  
  171.     if ( mCurrentTabID != 0 ) {
  172.         newTab = GetTab(mCurrentTabID);
  173.         if ( newTab != nil ) {
  174.             PaneIDT paneID = newTab->GetValueMessage();
  175.             if ( paneID != 0 ) {
  176.                 LPane *thePane = FindPaneByID(paneID);
  177.                 if ( thePane != nil ) {
  178.                     thePane->Show();
  179.                     if ( !RestoreLatentTabCommander(dynamic_cast<LView *>(thePane)) &&
  180.                          (theTabGroup != nil) ) {
  181.                          
  182.                         //StEmptyVisRgn emptyRgn(GetMacPort());    // Hide any flicker
  183.                         LCommander::SwitchTarget(theTabGroup);
  184.                     }
  185.                 }
  186.             }
  187.             newTab->SetTextTraitsID(GetTextTraitsID());
  188.             newTab->RefreshHiddenBottom();
  189.             BroadcastMessage(msg_TabViewChanged, this);
  190.         }
  191.     }
  192.     
  193.     if ( (lastTab != nil) || (newTab != nil) ) {
  194.         if ( lastTab != nil ) lastTab->Draw(nil);
  195.         if ( newTab != nil ) newTab->Draw(nil);
  196.         UpdatePort();
  197.     }
  198. }
  199.  
  200.  
  201. /*======================================================================================
  202.     Calculate the border rect, which will be offset by the bottom of the tabs.
  203. ======================================================================================*/
  204.  
  205. void CGATabBox::CalcBorderRect(Rect &outRect) {
  206.  
  207.     LGABox_fixes::CalcBorderRect(outRect);
  208.     
  209.     ::InsetRect(&outRect, 1, 1);    // For border
  210.     
  211.     Rect tabRect;
  212.     CalcCurrentTabRect(tabRect);
  213.  
  214.     outRect.top = tabRect.bottom - 4;
  215. }
  216.  
  217.  
  218. /*======================================================================================
  219.     Calculate the current tab rect in local coordinates.
  220. ======================================================================================*/
  221.  
  222. void CGATabBox::CalcCurrentTabRect(Rect &outRect) {
  223.  
  224.     Assert_(mCurrentTabID != 0);
  225.  
  226.     if ( mCurrentTabID ) {
  227.         CGATabBoxTab *theTab = GetTab(mCurrentTabID);
  228.         Assert_(theTab != nil);
  229.         if ( theTab != nil ) {
  230.             theTab->CalcPortFrameRect(outRect);
  231.             PortToLocalPoint(topLeft(outRect));
  232.             PortToLocalPoint(botRight(outRect));
  233.         }
  234.     }
  235. }
  236.  
  237.  
  238. /*======================================================================================
  239.     Finish creating the tab box.
  240. ======================================================================================*/
  241.  
  242. void CGATabBox::FinishCreateSelf(void) {
  243.  
  244.     LGABox_fixes::FinishCreateSelf();
  245.     
  246.     SetupTabs();
  247.     
  248.     SetCurrentTabID(GetUserCon());
  249. }
  250.  
  251.  
  252. /*======================================================================================
  253.     Draw the box border.
  254. ======================================================================================*/
  255.  
  256. void CGATabBox::DrawBoxBorder(void) {
  257.  
  258.     StColorPenState::Normalize();
  259.  
  260.     Rect borderRect;
  261.     CalcBorderRect(borderRect);
  262.     ::InsetRect(&borderRect, -1, -1);
  263.     
  264.     ::FrameRect(&borderRect);
  265.  
  266.     LGABox_fixes::DrawBoxBorder();
  267. }
  268.  
  269.  
  270. /*======================================================================================
  271.     Respond to tab messages. Only tabs will broadcast messages to this class, so that's
  272.     all we need to be concerned with.
  273. ======================================================================================*/
  274.  
  275. void CGATabBox::ListenToMessage(MessageT inMessage, void */*ioParam*/) {
  276.  
  277.     SetCurrentTabID((PaneIDT) inMessage);
  278. }
  279.  
  280.  
  281. /*======================================================================================
  282.     Called from FinishCreateSelf() to setup the tabs for the view.
  283. ======================================================================================*/
  284.  
  285. void CGATabBox::SetupTabs(void) {
  286.  
  287.     // Loop through all subpanes to find the relevant tabs
  288.     
  289.     LArrayIterator iterator(mSubPanes, LArrayIterator::from_Start);
  290.     LPane *theSub;
  291.     CGATabBoxTab *theTab = nil;
  292.     Boolean foundTabs = false;
  293.     while ( iterator.Next(&theSub) ) {
  294.         theTab = dynamic_cast<CGATabBoxTab *>(theSub);
  295.         if ( theTab != nil ) {
  296.             if ( theTab->GetValueMessage() != 0 ) {
  297.                 PaneIDT paneID = theTab->GetValueMessage();
  298.                 LPane *thePane = FindPaneByID(paneID);
  299.                 if ( thePane != nil ) {
  300.                     thePane->Hide();
  301.                     LView *theView = dynamic_cast<LView *>(thePane);
  302.                     if ( theView != nil ) {
  303.                         // Initialize the last active commander for the tab's pane
  304.                         TabLatentCommanderT rec = { paneID, 0 };
  305.                         mTabLatentCommanders.InsertItemsAt(1, LArray::index_Last, &rec);
  306.                     }
  307.                 }
  308.             }
  309.             theTab->SetTextTraitsID(GetTextTraitsID() + 1);
  310.             theTab->AddListener(this);
  311.             foundTabs = true;
  312.         }
  313.     }
  314.     Assert_(foundTabs);    // Should have found at least one tab!
  315. }
  316.  
  317.  
  318. /*======================================================================================
  319.     A new tab view has just been activated. Try to find the last active commander and
  320.     make it the currently active commander. Return true if a valid commander was actually
  321.     found and stored.
  322. ======================================================================================*/
  323.  
  324. Boolean CGATabBox::StoreLatentTabCommander(LView *inTabView) {
  325.  
  326.     if ( inTabView == nil ) return false;
  327.     
  328.     const Int32 count = mTabLatentCommanders.GetCount();
  329.     if ( count < 1 ) return false;
  330.     
  331.     PaneIDT paneID = inTabView->GetPaneID();
  332.     Int32 index = 1;
  333.  
  334.     // Try to find the tab pane id in our list
  335.     do {
  336.         if ( ((TabLatentCommanderT *) mTabLatentCommanders.GetItemPtr(index))->tabPaneID == paneID ) {
  337.             break;
  338.         }
  339.     } while ( ++index < count );
  340.     
  341.     paneID = 0;
  342.  
  343.     if ( index < count ) {
  344.         LCommander *curTarget = LCommander::GetTarget();
  345.         
  346.         if ( curTarget != nil ) {
  347.             LPane *thePane = dynamic_cast<LPane *>(curTarget);
  348.             if ( (thePane != nil) && thePane->IsEnabled() && 
  349.                  inTabView->FindPaneByID(thePane->GetPaneID()) ) {
  350.                 
  351.                 paneID = thePane->GetPaneID();    // We foud our commander!
  352.             }
  353.         }
  354.         
  355.         ((TabLatentCommanderT *) mTabLatentCommanders.GetItemPtr(index))->latentCommanderID = paneID;
  356.     }
  357.     
  358.     return (paneID != 0);
  359. }
  360.  
  361.  
  362. /*======================================================================================
  363.     A new tab view has just been activated. Try to find the last active commander and
  364.     make it the currently active commander. Return true if a valid commander was actually
  365.     found and restored.
  366. ======================================================================================*/
  367.  
  368. Boolean CGATabBox::RestoreLatentTabCommander(LView *inTabView) {
  369.  
  370.     if ( inTabView == nil ) return false;
  371.     
  372.     Int32 count = mTabLatentCommanders.GetCount();
  373.     if ( count < 1 ) return false;
  374.     
  375.     PaneIDT paneID = inTabView->GetPaneID();
  376.     Int32 index = 1;
  377.  
  378.     // Try to find the tab pane id in our list
  379.     do {
  380.         if ( ((TabLatentCommanderT *) mTabLatentCommanders.GetItemPtr(index))->tabPaneID == paneID ) {
  381.             break;
  382.         }
  383.     } while ( ++index < count );
  384.     
  385.     LCommander *theCommander = nil;
  386.  
  387.     if ( index < count ) {
  388.         PaneIDT latentCommanderID = ((TabLatentCommanderT *) mTabLatentCommanders.GetItemPtr(index))->latentCommanderID;
  389.         if ( latentCommanderID != 0 ) {
  390.             // We found our view, now see if there was an active commander
  391.             LPane *thePane = inTabView->FindPaneByID(latentCommanderID);
  392.             if ( (thePane != nil) && thePane->IsEnabled() ) {
  393.                 theCommander = dynamic_cast<LCommander *>(thePane);
  394.                 if ( theCommander != nil ) {
  395.                     LCommander::SwitchTarget(theCommander);
  396.                 }
  397.             }
  398.         }
  399.     }
  400.  
  401.     return (theCommander != nil);
  402. }
  403.  
  404.  
  405. /*======================================================================================
  406.     Get the specified tab. Return nil if the tab cannot be found.
  407. ======================================================================================*/
  408.  
  409. CGATabBoxTab *CGATabBox::GetTab(PaneIDT inID) {
  410.  
  411.     LArrayIterator iterator(mSubPanes, LArrayIterator::from_Start);
  412.     LPane *theSub;
  413.     while ( iterator.Next(&theSub) ) {
  414.         if ( theSub->GetPaneID() == inID ) {
  415.             CGATabBoxTab *theTab = dynamic_cast<CGATabBoxTab *>(theSub);
  416.             if ( theTab != nil ) return theTab;
  417.         }
  418.     }
  419.  
  420.     Assert_(false);    // Should have found tab!
  421.     return nil;
  422. }
  423.  
  424.  
  425. /*======================================================================================
  426.     Find the tab group for the window if it is currently active or nil if there is not 
  427.     one.
  428. ======================================================================================*/
  429.  
  430. LTabGroup *CGATabBox::FindTabGroup(void) {
  431.  
  432.     LCommander *theCommander = LCommander::GetTarget();
  433.     
  434.     if ( !theCommander ) return nil;
  435.     
  436.     LCommander *windowCommander = dynamic_cast<LCommander *>(LWindow::FetchWindowObject(GetMacPort()));
  437.     Assert_(windowCommander != nil);
  438.     
  439.     if ( windowCommander == theCommander ) return nil;
  440.     
  441.     LTabGroup *lastTabGroup = nil;
  442.     
  443.     do {
  444.         LTabGroup *tabGroup = dynamic_cast<LTabGroup *>(theCommander);
  445.         if ( tabGroup != nil ) {
  446.             lastTabGroup = tabGroup;
  447.         }
  448.     } while ( ((theCommander = theCommander->GetSuperCommander()) != nil) &&
  449.               (theCommander != windowCommander) );
  450.  
  451.     return lastTabGroup;
  452. }
  453.  
  454.  
  455. #pragma mark -
  456.  
  457. /*======================================================================================
  458.     Refresh just the bottom portion of the button.
  459. ======================================================================================*/
  460.  
  461. void CGATabBoxTab::RefreshHiddenBottom(void) {
  462.  
  463.     Rect refreshRect;
  464.     if ( IsVisible() && CalcPortFrameRect(refreshRect) ) {
  465.         refreshRect.top = refreshRect.bottom - 5;
  466.         Rect superRevealed;
  467.         mSuperView->GetRevealedRect(superRevealed);
  468.         if ( ::SectRect(&refreshRect, &superRevealed, &refreshRect) ) {
  469.             InvalPortRect(&refreshRect);
  470.         }
  471.     }
  472. }
  473.  
  474.  
  475. /*======================================================================================
  476.     Draw the button except for the bottom edge.
  477. ======================================================================================*/
  478.  
  479. void CGATabBoxTab::DrawSelf(void) {
  480.  
  481.     Rect clipRect;
  482.     CalcLocalFrameRect(clipRect);
  483.     
  484.     RgnHandle clipRgn = ::NewRgn();
  485.     
  486.     if ( IsSelectedTab() ) {
  487.         RgnHandle tempRgn = ::NewRgn();
  488.         clipRect.bottom -= 4;
  489.         ::RectRgn(clipRgn, &clipRect);
  490.         ::SetRect(&clipRect, clipRect.left + 1, clipRect.bottom, clipRect.right - 4, clipRect.bottom + 1);
  491.         ::RectRgn(tempRgn, &clipRect);
  492.         ::UnionRgn(clipRgn, tempRgn, clipRgn);
  493.         ::DisposeRgn(tempRgn);
  494.     } else {
  495.         clipRect.bottom -= 5;
  496.         ::RectRgn(clipRgn, &clipRect);
  497.     }
  498.     
  499.     StClipRgnState saveClip(clipRgn);
  500.     ::DisposeRgn(clipRgn);
  501.  
  502.     LGAPushButton::DrawSelf();
  503. }
  504.  
  505.  
  506. /*======================================================================================
  507.     Clicking atomatically selects.
  508. ======================================================================================*/
  509.  
  510. void CGATabBoxTab::ClickSelf(const SMouseDownEvent &/*inMouseDown*/) {
  511.  
  512.     BroadcastValueMessage();
  513. }
  514.  
  515.  
  516. /*======================================================================================
  517.     Broadcast pane id instead of value message.
  518. ======================================================================================*/
  519.  
  520. void CGATabBoxTab::BroadcastValueMessage(void) {
  521.  
  522.     MessageT valueMsg = mValueMessage;
  523.     BroadcastMessage(mPaneID, &mValueMessage);
  524. }
  525.  
  526.  
  527. /*======================================================================================
  528.     Offset since hiding a portion of button.
  529. ======================================================================================*/
  530.  
  531. void CGATabBoxTab::CalcTitleRect(Rect &outRect) {
  532.  
  533.     LGAPushButton::CalcTitleRect(outRect);
  534.     
  535.     if ( IsSelectedTab() ) {
  536.         ::OffsetRect(&outRect, 0, -1);
  537.     } else {
  538.         ::OffsetRect(&outRect, 0, -2);
  539.     }
  540. }
  541.  
  542.  
  543. /*======================================================================================
  544.     Draw darker if not selected. Direct copy/paste from LGAPushButton except for 
  545.     IsSelectedTab() sections.
  546. ======================================================================================*/
  547.  
  548. void CGATabBoxTab::DrawButtonNormalColor(void) {
  549.  
  550.     StColorPenState    theColorPenState;
  551.     theColorPenState.Normalize();
  552.     
  553.     Boolean isSelected = IsSelectedTab();
  554.         
  555.     Rect localFrame;
  556.     CalcLocalFrameRect ( localFrame );
  557.     
  558.     ::RGBForeColor (&UGAColorRamp::GetBlackColor());
  559.     ::FrameRoundRect (&localFrame, 8, 8);
  560.  
  561.     if ( isSelected ) {
  562.         ::RGBForeColor(&UGAColorRamp::GetColor(2));
  563.     } else {
  564.         ::RGBForeColor(&UGAColorRamp::GetColor(3));
  565.     }
  566.     ::InsetRect(&localFrame, 1, 1);
  567.     ::PaintRoundRect(&localFrame, 4, 4);
  568.     ::InsetRect(&localFrame, -1, -1);
  569.     
  570.     if ( isSelected ) {
  571.         ::RGBForeColor(&UGAColorRamp::GetWhiteColor());
  572.     } else {
  573.         ::RGBForeColor(&UGAColorRamp::GetColor(1));
  574.     }
  575.     UGraphicsUtilities::TopLeftSide (&localFrame, 
  576.                         2,                     //    TOP
  577.                         2,                     //    LEFT
  578.                         3,                     // BOTTOM
  579.                         3 );                    // RIGHT
  580.     UGraphicsUtilities::PaintColorPixel (     localFrame.left + 3, localFrame.top + 3, &UGAColorRamp::GetWhiteColor());
  581.     UGraphicsUtilities::PaintColorPixel (     localFrame.left + 1, localFrame.top + 2, &UGAColorRamp::GetColor(4));
  582.     UGraphicsUtilities::PaintColorPixel (     localFrame.left + 2, localFrame.top + 1, &UGAColorRamp::GetColor(4));
  583.     UGraphicsUtilities::PaintColorPixel (     localFrame.left + 1, localFrame.bottom - 3, &UGAColorRamp::GetColor(4));
  584.     UGraphicsUtilities::PaintColorPixel (     localFrame.left + 2, localFrame.bottom - 2, &UGAColorRamp::GetColor(4));
  585.     UGraphicsUtilities::PaintColorPixel (     localFrame.right - 3, localFrame.top + 1, &UGAColorRamp::GetColor(4));
  586.     UGraphicsUtilities::PaintColorPixel (     localFrame.right - 2, localFrame.top + 2, &UGAColorRamp::GetColor(4));
  587.  
  588.     // Ñ SHADOW EDGES
  589.     ::RGBForeColor ( &UGAColorRamp::GetColor(8));
  590.     ::MoveTo ( localFrame.left + 3, localFrame.bottom - 2 );
  591.     ::LineTo ( localFrame.right - 3, localFrame.bottom - 2 );
  592.     ::MoveTo ( localFrame.right - 2, localFrame.bottom - 3 );
  593.     ::LineTo ( localFrame.right - 2, localFrame.top + 3 );
  594.     ::RGBForeColor ( &UGAColorRamp::GetColor(5));
  595.     UGraphicsUtilities::BottomRightSide ( &localFrame, 
  596.                             3,                     //    TOP
  597.                             3,                     //    LEFT
  598.                             2,                     // BOTTOM
  599.                             2 );                    // RIGHT
  600.     UGraphicsUtilities::PaintColorPixel (     localFrame.right - 3, localFrame.bottom - 3, &UGAColorRamp::GetColor(8));
  601.     UGraphicsUtilities::PaintColorPixel (     localFrame.right - 4, localFrame.bottom - 4, &UGAColorRamp::GetColor(5));
  602. }
  603.  
  604.  
  605.