home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / mac / UserInterface / CTabControl.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  28.9 KB  |  974 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. #ifdef PowerPlant_PCH
  20. #include PowerPlant_PCH
  21. #endif
  22.  
  23. #include <LArray.h>
  24. #include <LArrayIterator.h>
  25. #include <LDataStream.h>
  26. #include <PP_Messages.h>
  27. #include <UDrawingState.h>
  28. #include <URegions.h>
  29. #include <UResourceMgr.h>
  30. #include <UGWorld.h>
  31. #include <UTextTraits.h>
  32.  
  33. #include "CTabControl.h"
  34. #include "UStdBevels.h"
  35. #include "UGraphicGizmos.h"
  36.  
  37. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  38. //    Ñ    
  39. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  40.  
  41. CTabControl::CTabControl(LStream* inStream)
  42.     :    LControl(inStream),
  43.         mTabs(sizeof(CTabInstance*))
  44. {
  45.     *inStream >> mOrientation;
  46.     *inStream >> mCornerPixels;
  47.     *inStream >> mBevelDepth;
  48.     *inStream >> mSpacing;
  49.     *inStream >> mLeadPixels;
  50.     *inStream >> mRisePixels;
  51.     
  52.     ResIDT theBevelTraitsID;
  53.     *inStream >> theBevelTraitsID;
  54.     UGraphicGizmos::LoadBevelTraits(theBevelTraitsID, mActiveColors);
  55.  
  56.     *inStream >> theBevelTraitsID;
  57.     UGraphicGizmos::LoadBevelTraits(theBevelTraitsID, mOtherColors);
  58.  
  59.     *inStream >> mTabDescID;
  60.     *inStream >> mTitleTraitsID;
  61.     mControlMask = ::NewRgn();
  62.     ThrowIfNULL_(mControlMask);
  63.  
  64.     mCurrentTab = NULL;
  65.     mTrackInside = false;
  66.     mBevelSides.left = true;
  67.     mBevelSides.top = true;
  68.     mBevelSides.right = true;
  69.     mBevelSides.bottom = true;
  70.     mMinimumSize.h = mMinimumSize.v = -1;
  71. }
  72.  
  73. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  74. //    Ñ    
  75. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  76.  
  77. CTabControl::~CTabControl()
  78. {
  79.     if (mControlMask != NULL)
  80.         ::DisposeRgn(mControlMask);
  81.         
  82.     CTabInstance* theTab;
  83.     LArrayIterator theIter(mTabs, LArrayIterator::from_Start);
  84.     while (theIter.Next(&theTab))
  85.         delete theTab;
  86. }
  87.  
  88. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  89. //    Ñ    
  90. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  91.  
  92. void CTabControl::FinishCreateSelf(void)
  93. {
  94.     LControl::FinishCreateSelf();
  95.     
  96.     if (mTabDescID != 0)
  97.         DoLoadTabs(mTabDescID);    
  98. }
  99.  
  100. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  101. //    Ñ    
  102. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  103.  
  104. void CTabControl::DoLoadTabs(ResIDT inTabDescResID)
  105. {
  106.     Assert_(inTabDescResID != 0);
  107.     
  108.     CTabInstance* theTab;
  109.     LArrayIterator theIter(mTabs, LArrayIterator::from_Start);
  110.     while (theIter.Next(&theTab))
  111.         delete theTab;
  112.  
  113.     mTabDescID = inTabDescResID;
  114.     StResource theTabRes(ResType_TabDescList, mTabDescID);
  115.     {
  116.         StHandleLocker theLock(theTabRes);
  117.         LDataStream theTabStream(*theTabRes.mResourceH, ::GetHandleSize(theTabRes));
  118.         Int16 bevelSubCount = theTabStream.GetLength() / sizeof(STabDescriptor);
  119.         for (Int32 index = 0; index < bevelSubCount; index++)
  120.             {
  121.             STabDescriptor theDesc;
  122.             theTabStream.ReadData(&theDesc, sizeof(STabDescriptor));
  123.             CTabInstance* theTab;
  124.             if (theDesc.width == -2) 
  125.                 theTab = new CIconTabInstance(theDesc);
  126.             else
  127.                 theTab = new CTextTabInstance(theDesc);
  128.             mTabs.InsertItemsAt(1, LArray::index_Last, &theTab);
  129.             }
  130.     }
  131.  
  132.     Recalc();
  133.  
  134. // don't call SetMinValue and SetMaxValue as they may do range-checking which may
  135. // not work if the resources haven't set good initial values
  136. // this is ok since we are setting all 3 values at the same time
  137.     mMinValue = 1;
  138.     mMaxValue = mTabs.GetCount();
  139. #if 0
  140.     SetMaxValue(mTabs.GetCount());
  141.     SetMinValue(1);
  142. #endif
  143.     SetValue(mValue);
  144. }
  145.  
  146. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  147. //    Ñ    
  148. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  149.  
  150. void CTabControl::Draw(RgnHandle inSuperDrawRgnH)
  151. {
  152.     Rect theFrame;
  153.     if ((mVisible == triState_On) && CalcPortFrameRect(theFrame) && ((inSuperDrawRgnH == nil) ||
  154.             RectInRgn(&theFrame, inSuperDrawRgnH)) && FocusDraw())
  155.         {
  156.         PortToLocalPoint(topLeft(theFrame));    // Get Frame in Local coords
  157.         PortToLocalPoint(botRight(theFrame));
  158.     
  159.         if (ExecuteAttachments(msg_DrawOrPrint, &theFrame))
  160.             {
  161.             Boolean bDidDraw = false;
  162.  
  163.             StColorPenState thePenSaver;
  164.             StColorPenState::Normalize();
  165.             
  166.             // Fail safe offscreen drawing
  167.             StValueChanger<EDebugAction> okayToFail(gDebugThrow, debugAction_Nothing);
  168.             try
  169.                 {            
  170.                 LGWorld theOffWorld(theFrame, 0, useTempMem);
  171.  
  172.                 if (!theOffWorld.BeginDrawing())
  173.                     throw memFullErr;
  174.                     
  175.                 DrawSelf();
  176.                     
  177.                 theOffWorld.EndDrawing();
  178.                 theOffWorld.CopyImage(GetMacPort(), theFrame, srcCopy, mControlMask);
  179.                 bDidDraw = true;
  180.                 }
  181.             catch (...)
  182.                 {
  183.                 Assert_(false);
  184.                 //     & draw onscreen
  185.                 }
  186.                 
  187.             if (!bDidDraw)
  188.                 DrawSelf();
  189.             }
  190.         }
  191. }
  192.  
  193. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  194. //    Ñ    
  195. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  196.  
  197. void CTabControl::DrawSelf(void)
  198. {
  199.     CTabInstance* theTab;
  200.     LArrayIterator theIter(mTabs, LArrayIterator::from_Start);
  201.     while (theIter.Next(&theTab))
  202.         {
  203.         if (theTab != mCurrentTab)
  204.             // FIX ME!!! we could check to see if the tab's mask intersects
  205.             // the local update region
  206.             DrawOneTab(theTab);
  207.         }
  208.  
  209.     Rect theControlFrame;
  210.     CalcLocalFrameRect(theControlFrame);
  211.     
  212.     // Need to draw the current tab last otherwise the
  213.     // single pixel black border lines won't get drawn right
  214.     DrawOneTab(mCurrentTab);
  215.     
  216.     SetClipForDrawingSides();
  217.     DrawSides();
  218. }
  219.  
  220. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  221. //    Ñ    
  222. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  223.  
  224. void CTabControl::DrawOneTabBackground(
  225.     RgnHandle inRegion,
  226.     Boolean inCurrentTab)
  227. {
  228.     SBevelColorDesc& theTabColors = inCurrentTab ? mActiveColors : mOtherColors;
  229.     Int16 thePaletteIndex = theTabColors.fillColor;
  230.     if (mTrackInside)
  231.         thePaletteIndex--;
  232.     ::PmForeColor(thePaletteIndex);
  233.     ::PaintRgn(inRegion);
  234. }
  235.  
  236. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  237. //    Ñ    
  238. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  239.  
  240. void CTabControl::DrawOneTabFrame(RgnHandle inRegion, Boolean inCurrentTab)
  241. {
  242.     // Draw the tab frame    
  243.     SBevelColorDesc& theTabColors = inCurrentTab ? mActiveColors : mOtherColors;
  244.     Int16 thePaletteIndex = theTabColors.frameColor;
  245.     ::PmForeColor(thePaletteIndex);
  246.     ::FrameRgn(inRegion);
  247. }
  248.  
  249. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  250. //    Ñ    
  251. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  252.  
  253. void CTabControl::DrawCurrentTabSideClip(RgnHandle inRegion)
  254. {
  255.     // Always only for the current tab
  256.     ::SetClip(inRegion);
  257.     ::PmForeColor(mActiveColors.fillColor);
  258.     ::PaintRect(&mSideClipFrame);
  259. }
  260.  
  261. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  262. //    Ñ    
  263. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  264.  
  265.  
  266. void CTabControl::DrawOneTab(CTabInstance* inTab)
  267. {
  268.     StClipRgnState theClipSaver;
  269.  
  270.     Rect theControlFrame;
  271.     CalcLocalFrameRect(theControlFrame);
  272.  
  273.     Boolean isCurrentTab = (inTab == mCurrentTab);
  274.     if (isCurrentTab)
  275.         {
  276.         StRegion theTempMask(inTab->mMask);
  277.         StRegion theSideMask(mSideClipFrame);
  278.         ::DiffRgn(theTempMask, theSideMask, theTempMask);
  279.         ::SetClip(theTempMask);
  280.         }
  281.     else
  282.         {
  283.         StRegion theTempMask(inTab->mMask);
  284.         ::DiffRgn(theTempMask, mCurrentTab->mMask, theTempMask);
  285.         ::SetClip(theTempMask);
  286.         }
  287.     
  288.     // This draws the fill pattern in the tab    
  289.     DrawOneTabBackground(inTab->mMask, isCurrentTab);
  290.     // This just calls FrameRgn on inTab->mMask
  291.     DrawOneTabFrame(inTab->mMask, isCurrentTab);
  292.  
  293.     StColorPenState thePenSaver;
  294.     thePenSaver.Normalize();
  295.  
  296.     if (isCurrentTab)
  297.         DrawCurrentTabSideClip(inTab->mMask);
  298.  
  299.     // Draw the title before the bevel because the bevel needs to futz
  300.     // with the clip
  301.     inTab->DrawTitle(mCurrentTab, mTitleTraitsID);
  302.  
  303.     if (mBevelDepth > 0)
  304.     {
  305.  
  306.         ::PenSize(mBevelDepth, mBevelDepth);
  307.  
  308.         if (isCurrentTab) {
  309.             // Draw the top bevel        
  310.             RGBColor    theAddColor = {0x4000, 0x4000, 0x4000};
  311.             ::RGBForeColor(&theAddColor);
  312.             ::OpColor(&UGraphicGizmos::sLighter);
  313.             ::PenMode(subPin);
  314.             
  315.             // This runs the pen around the top and left sides
  316.             DrawTopBevel(inTab);
  317.         }
  318.  
  319.         // Draw the bevel shadow
  320.         StRegion theShadeRgn(inTab->mShadeFrame);
  321.         
  322.         if (inTab != mCurrentTab)
  323.             ::DiffRgn(theShadeRgn, mCurrentTab->mMask, theShadeRgn); 
  324.  
  325.         ::SetClip(theShadeRgn);
  326.         // Set up the colors for the bevel shadow
  327.         RGBColor    theSubColor = {0x4000, 0x4000, 0x4000};
  328.         ::RGBForeColor(&theSubColor);
  329.         ::OpColor(&UGraphicGizmos::sDarker);
  330.         ::PenMode(subPin);
  331.         // This runs the pen around the bottom and right sides
  332.         DrawBottomBevel(inTab, isCurrentTab);
  333.     }
  334. }
  335.  
  336. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  337. //    Ñ    
  338. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  339.  
  340. void CTabControl::Recalc(void)
  341. {
  342.     FocusDraw();
  343.     ::SetEmptyRgn(mControlMask);
  344.  
  345.     Rect theControlFrame;
  346.     CalcLocalFrameRect(theControlFrame);
  347.     mSideClipFrame = theControlFrame;
  348.     
  349.     Int16 theExtendFactor = mBevelDepth + mRisePixels;
  350.     Point theBasePoint;
  351.     switch (mOrientation)
  352.         {
  353.         case eNorthTab:
  354.             theBasePoint.h = theControlFrame.left + mLeadPixels;
  355.             theBasePoint.v = theControlFrame.bottom;
  356.             mBevelSides.bottom = false;
  357.             mSideClipFrame.top = mSideClipFrame.bottom - theExtendFactor;
  358.             mSideClipFrame.bottom += mBevelDepth;
  359.             ::InsetRect(&mSideClipFrame, 1, 0);
  360.             break;
  361.             
  362.         case eEastTab:
  363.             theBasePoint.h = theControlFrame.left;
  364.             theBasePoint.v = theControlFrame.top + mLeadPixels;
  365.             mBevelSides.left = false;
  366.             mSideClipFrame.right = mSideClipFrame.left + theExtendFactor;
  367.             mSideClipFrame.left -= mBevelDepth;
  368.             ::InsetRect(&mSideClipFrame, 0, 1);
  369.             break;
  370.                         
  371.         case eSouthTab:
  372.             theBasePoint.h = theControlFrame.left + mLeadPixels;
  373.             theBasePoint.v = theControlFrame.top;
  374.             mBevelSides.top = false;
  375.             mSideClipFrame.bottom = mSideClipFrame.top + theExtendFactor;
  376.             mSideClipFrame.top -= mBevelDepth;
  377.             ::InsetRect(&mSideClipFrame, 1, 0);
  378.             break;
  379.  
  380.         case eWestTab:
  381.             theBasePoint.h = theControlFrame.right;
  382.             theBasePoint.v = theControlFrame.top + mLeadPixels;
  383.             mBevelSides.right = false;
  384.             mSideClipFrame.left = mSideClipFrame.right - theExtendFactor;
  385.             mSideClipFrame.right += mBevelDepth;
  386.             ::InsetRect(&mSideClipFrame, 0, 1);
  387.             break;
  388.         }
  389.  
  390.     // Set the Title traits becuase we may need to calculate width based on
  391.     // title dimensions
  392.     UTextTraits::SetPortTextTraits(mTitleTraitsID);
  393.  
  394.     CTabInstance* theTab;
  395.     LArrayIterator theIter(mTabs, LArrayIterator::from_Start);
  396.     while (theIter.Next(&theTab))
  397.         {
  398.         theTab->mFrame = theControlFrame;
  399.  
  400.         if (theTab->mMask == NULL)
  401.             theTab->mMask = ::NewRgn();
  402.         ThrowIfNULL_(theTab->mMask);
  403.  
  404.         Int16 theWidth;
  405.         // Size to title if we are in a norh or south orientation, and the width is flagged appropriately
  406.         if (((mOrientation == eNorthTab) || (mOrientation == eSouthTab)) && (theTab->mWidth == -1))
  407.             {
  408.             theWidth = ::StringWidth(theTab->mTitle) + (4 * ::CharWidth('W'));
  409.             }
  410.         else
  411.             theWidth = theTab->mWidth;
  412.         
  413.         switch (mOrientation)
  414.             {
  415.             case eNorthTab:
  416.                 theTab->mFrame.left = theBasePoint.h;
  417.                 theTab->mFrame.right = theTab->mFrame.left + theWidth;
  418.                 theTab->mFrame.bottom -= mBevelDepth + mRisePixels;
  419.                 theBasePoint.h = theTab->mFrame.right + mSpacing;
  420.                 theTab->mShadeFrame = theTab->mFrame;
  421.                 theTab->mShadeFrame.left = theTab->mShadeFrame.right - (mCornerPixels + mBevelDepth);
  422.                 break;
  423.                 
  424.             case eEastTab:
  425.                 theTab->mFrame.top = theBasePoint.v;
  426.                 theTab->mFrame.bottom = theTab->mFrame.top + theWidth; // or in this case height
  427.                 theTab->mFrame.left += mBevelDepth + mRisePixels;
  428.                 theBasePoint.v = theTab->mFrame.bottom + mSpacing;
  429.                 theTab->mShadeFrame = theTab->mFrame;
  430.                 theTab->mShadeFrame.top += mCornerPixels + (mBevelDepth - 1);
  431.                 break;
  432.                             
  433.             case eSouthTab:
  434.                 theTab->mFrame.left = theBasePoint.h;
  435.                 theTab->mFrame.top += mBevelDepth + mRisePixels;
  436.                 theTab->mFrame.right = theTab->mFrame.left + theWidth;
  437.                 theBasePoint.h = theTab->mFrame.right + mSpacing;
  438.                 theTab->mShadeFrame = theTab->mFrame;
  439.                 theTab->mShadeFrame.left += mCornerPixels + (mBevelDepth - 1);
  440.                 break;
  441.  
  442.             case eWestTab:
  443.                 theTab->mFrame.top = theBasePoint.v;
  444.                 theTab->mFrame.bottom = theTab->mFrame.top + theWidth; // or in this case height
  445.                 theTab->mFrame.right -= mBevelDepth + mRisePixels;
  446.                 theBasePoint.v = theTab->mFrame.bottom + mSpacing;
  447.                 theTab->mShadeFrame = theTab->mFrame;
  448.                 theTab->mShadeFrame.top = theTab->mShadeFrame.bottom - (mCornerPixels + mBevelDepth);
  449.                 break;
  450.             }
  451.  
  452.         CalcTabMask(theControlFrame, theTab->mFrame, theTab->mMask);
  453.         ::UnionRgn(mControlMask, theTab->mMask, mControlMask);
  454.  
  455.         // Here we conpensate for the 1 pixel frame.  Since drawing is done below and to
  456.         // the left of a pixel, we need to adjust the right and bottom of the frame so
  457.         // the frame relative drawing will be inside the tab mask region.
  458.         theTab->mFrame.right--;
  459.         theTab->mFrame.bottom--; 
  460.         }
  461.     if ( theTab )
  462.         switch ( mOrientation )    {
  463.             case eNorthTab:
  464.             case eSouthTab:
  465.                 mMinimumSize.h = theTab->mFrame.right + 8;
  466.                 mMinimumSize.v = theTab->mFrame.bottom - theTab->mFrame.top;
  467.                 break;
  468.             case eEastTab:
  469.             case eWestTab:
  470.                 mMinimumSize.h = theTab->mFrame.right - theTab->mFrame.left + 8;
  471.                 mMinimumSize.v = theTab->mFrame.bottom;
  472.                 break;
  473.         }
  474. }
  475.  
  476. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  477. //    Ñ    
  478. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  479.  
  480. void CTabControl::CalcTabMask(
  481.     const Rect&     inControlFrame,
  482.     const Rect&        inTabFrame,
  483.     RgnHandle        ioTabMask)
  484. {
  485.     ::RectRgn(ioTabMask, &inControlFrame);
  486.  
  487.     StRegion theTempRgn1, theTempRgn2;
  488.     
  489.     // when we subtract 1 from the tab frame, it's to accomodate for the frame
  490.     // which draws to the left and below the actual pixel
  491.     
  492.     switch (mOrientation)
  493.         {
  494.         case eNorthTab:
  495.             ::SetRectRgn(theTempRgn1, inControlFrame.left, inControlFrame.top, inTabFrame.left, inTabFrame.bottom - 1);
  496.             ::SetRectRgn(theTempRgn2, inTabFrame.right, inControlFrame.top, inControlFrame.right, inTabFrame.bottom - 1);
  497.             break;
  498.             
  499.         case eEastTab:
  500.             ::SetRectRgn(theTempRgn1, inTabFrame.left + 1, inControlFrame.top, inControlFrame.right, inTabFrame.top);
  501.             ::SetRectRgn(theTempRgn2, inTabFrame.left + 1, inTabFrame.bottom, inControlFrame.right, inControlFrame.bottom);
  502.             break;
  503.                         
  504.         case eSouthTab:
  505.             ::SetRectRgn(theTempRgn1, inControlFrame.left, inTabFrame.top + 1, inTabFrame.left, inControlFrame.bottom);
  506.             ::SetRectRgn(theTempRgn2, inTabFrame.right, inTabFrame.top + 1, inControlFrame.right, inControlFrame.bottom);
  507.             break;
  508.  
  509.         case eWestTab:
  510.             ::SetRectRgn(theTempRgn1, inControlFrame.left, inControlFrame.top, inTabFrame.right - 1, inTabFrame.top);
  511.             ::SetRectRgn(theTempRgn2, inControlFrame.left, inTabFrame.bottom, inTabFrame.right - 1, inControlFrame.bottom);
  512.             break;
  513.         }
  514.  
  515.     ::DiffRgn(ioTabMask, theTempRgn1, ioTabMask);
  516.     ::DiffRgn(ioTabMask, theTempRgn2, ioTabMask);
  517.  
  518.     // Knock off the corners of the tab
  519.     ::OpenRgn();
  520.     
  521.     if ((mOrientation == eWestTab) || (mOrientation == eNorthTab))
  522.         {
  523.         ::MoveTo(inTabFrame.left, inTabFrame.top);
  524.         ::LineTo(inTabFrame.left + mCornerPixels, inTabFrame.top);
  525.         ::LineTo(inTabFrame.left, inTabFrame.top + mCornerPixels);
  526.         ::LineTo(inTabFrame.left, inTabFrame.top);
  527.         }
  528.         
  529.     if ((mOrientation == eNorthTab) || (mOrientation == eEastTab))
  530.         {
  531.         ::MoveTo(inTabFrame.right, inTabFrame.top);
  532.         ::LineTo(inTabFrame.right, inTabFrame.top + mCornerPixels);
  533.         ::LineTo(inTabFrame.right - (mCornerPixels + 1), inTabFrame.top);
  534.         ::LineTo(inTabFrame.right, inTabFrame.top);
  535.         }
  536.  
  537.     if ((mOrientation == eEastTab) || (mOrientation == eSouthTab))
  538.         {
  539.         ::MoveTo(inTabFrame.right, inTabFrame.bottom);
  540.         ::LineTo(inTabFrame.right - (mCornerPixels + 1), inTabFrame.bottom);
  541.         ::LineTo(inTabFrame.right, inTabFrame.bottom - (mCornerPixels + 1));
  542.         ::LineTo(inTabFrame.right, inTabFrame.bottom);
  543.         }
  544.  
  545.     if ((mOrientation == eSouthTab) || (mOrientation == eWestTab))
  546.         {
  547.         ::MoveTo(inTabFrame.left, inTabFrame.bottom);
  548.         ::LineTo(inTabFrame.left, inTabFrame.bottom - mCornerPixels);
  549.         ::LineTo(inTabFrame.left + mCornerPixels, inTabFrame.bottom);
  550.         ::LineTo(inTabFrame.left, inTabFrame.bottom);
  551.         }
  552.         
  553.     ::CloseRgn(theTempRgn1);
  554.     ::DiffRgn(ioTabMask, theTempRgn1, ioTabMask);
  555. }
  556.  
  557. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  558. //    Ñ    
  559. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  560.  
  561. void CTabControl::DrawTopBevel(CTabInstance* inTab)
  562. {
  563.     const Rect& theTabFrame = inTab->mFrame;
  564.     switch (mOrientation)
  565.         {
  566.         case eNorthTab:
  567.             {
  568.             ::MoveTo(theTabFrame.left + 1, theTabFrame.bottom + 1);
  569.             ::LineTo(theTabFrame.left + 1, theTabFrame.top + mCornerPixels);
  570.             ::LineTo(theTabFrame.left + mCornerPixels, theTabFrame.top + 1);
  571.             ::LineTo(theTabFrame.right - (mCornerPixels + mBevelDepth) + 1, theTabFrame.top + 1);
  572.             }
  573.             break;
  574.  
  575.         case eEastTab:
  576.             {
  577.             // I'm not sure whether this is quite right...
  578.             ::MoveTo(theTabFrame.left - 1, theTabFrame.top + 1);
  579.             ::LineTo(theTabFrame.right - (mCornerPixels + mBevelDepth) + 1, theTabFrame.top + 1);
  580.             ::LineTo(theTabFrame.right - mBevelDepth, theTabFrame.top + mCornerPixels);
  581.             }
  582.             break;
  583.             
  584.         case eSouthTab:
  585.             {
  586.             // I'm not sure whether this is quite right...
  587.             ::MoveTo(theTabFrame.left + 1, theTabFrame.top - 1);
  588.             ::LineTo(theTabFrame.left + 1, theTabFrame.bottom - (mCornerPixels + mBevelDepth) + 1);
  589.             ::LineTo(theTabFrame.left + mCornerPixels, theTabFrame.bottom - mBevelDepth);
  590.             }
  591.             break;
  592.         
  593.         case eWestTab:
  594.             {
  595.             ::MoveTo(theTabFrame.right + 1, theTabFrame.top + 1);
  596.             ::LineTo(theTabFrame.left + mCornerPixels, theTabFrame.top + 1);
  597.             ::LineTo(theTabFrame.left + 1, theTabFrame.top + mCornerPixels);
  598.             ::LineTo(theTabFrame.left + 1, theTabFrame.bottom - (mCornerPixels + mBevelDepth) + 1);
  599.             }
  600.             break;
  601.         }
  602. }
  603.  
  604. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  605. //    Ñ    DrawBottomBevel
  606. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  607.  
  608. void CTabControl::DrawBottomBevel(CTabInstance* inTab, Boolean    inCurrentTab)
  609. {
  610.     const Rect& theTabFrame = inTab->mFrame;
  611.     switch (mOrientation)
  612.         {
  613.         case eNorthTab:
  614.             {
  615.             ::MoveTo(theTabFrame.right - mBevelDepth, theTabFrame.top + mCornerPixels);
  616.             ::LineTo(theTabFrame.right - mBevelDepth, theTabFrame.bottom + 1);
  617.             }
  618.             break;
  619.  
  620.         case eEastTab:
  621.             {
  622.             // I'm not sure whether this is quite right...
  623.             ::MoveTo(theTabFrame.right - mBevelDepth, theTabFrame.top + mCornerPixels);            
  624.             ::LineTo(theTabFrame.right - mBevelDepth, theTabFrame.bottom - (mCornerPixels + mBevelDepth) + 1);
  625.             ::LineTo(theTabFrame.right - (mCornerPixels + mBevelDepth) + 1, theTabFrame.bottom - mBevelDepth);
  626.             ::LineTo(theTabFrame.left - 1, theTabFrame.bottom - mBevelDepth);
  627.             }
  628.             break;
  629.             
  630.         case eSouthTab:
  631.             {
  632.             // I'm not sure whether this is quite right...
  633.             ::MoveTo(theTabFrame.left + mCornerPixels, theTabFrame.bottom - mBevelDepth);
  634.             ::LineTo(theTabFrame.right - (mCornerPixels + mBevelDepth) + 1, theTabFrame.bottom - mBevelDepth);
  635.             ::LineTo(theTabFrame.right - mBevelDepth, theTabFrame.bottom - (mCornerPixels + mBevelDepth) + 1);
  636.             ::LineTo(theTabFrame.right - mBevelDepth, theTabFrame.top - 1);
  637.             }
  638.             break;
  639.         
  640.         case eWestTab:
  641.             {
  642.             ::MoveTo(theTabFrame.left + mCornerPixels, theTabFrame.bottom - mBevelDepth);
  643.             ::LineTo(theTabFrame.right + 1, theTabFrame.bottom - mBevelDepth);
  644.             }
  645.             break;
  646.         }
  647. }
  648.  
  649. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  650. //    Ñ    
  651. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  652. void CTabControl::SetClipForDrawingSides(void)
  653. {
  654.     Assert_(mCurrentTab != NULL);
  655.  
  656.     Rect theTempTabFrame = mCurrentTab->mFrame;
  657.     Int16 theExtendFactor = mBevelDepth + mRisePixels;
  658.     
  659.     switch (mOrientation)
  660.         {
  661.         case eNorthTab:
  662.             theTempTabFrame.bottom += theExtendFactor;
  663.             theTempTabFrame.right -= mBevelDepth;
  664.             theTempTabFrame.left += mBevelDepth + 1;
  665.             break;
  666.  
  667.         case eEastTab:
  668.             theTempTabFrame.left -= theExtendFactor;
  669.             theTempTabFrame.top += mBevelDepth + 1;
  670.             theTempTabFrame.bottom -= mBevelDepth;
  671.             break;
  672.             
  673.         case eSouthTab:
  674.             theTempTabFrame.top -= theExtendFactor;
  675.             theTempTabFrame.right -= mBevelDepth;
  676.             theTempTabFrame.left += mBevelDepth + 1;
  677.             break;
  678.         
  679.         case eWestTab:
  680.             theTempTabFrame.right += theExtendFactor;
  681.             theTempTabFrame.top += mBevelDepth + 1;
  682.             theTempTabFrame.bottom -= mBevelDepth;
  683.             break;
  684.         
  685.         }
  686.  
  687.     StRegion theTabFrameMask(theTempTabFrame);
  688.     StRegion theSideClipMask(mSideClipFrame);
  689.     ::DiffRgn(theSideClipMask, theTabFrameMask, theSideClipMask);
  690.     ::SectRgn(theSideClipMask, mCurrentTab->mMask, theSideClipMask);
  691.     ::SetClip(theSideClipMask);    
  692. }
  693.  
  694. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  695. //    Ñ    
  696. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  697. void CTabControl::DrawSides(void)
  698. {
  699.     UGraphicGizmos::BevelTintRect(mSideClipFrame, mBevelDepth, 0x4000, 0x4000);
  700. }
  701.  
  702.  
  703. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  704. //    Ñ    
  705. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  706.  
  707. Int16 CTabControl::FindHotSpot(Point inPoint)
  708. {
  709.     Assert_(mCurrentTab != NULL);
  710.     
  711.     // Since the regions overlap, check the currently selected tab's region
  712.     // before checking the others.
  713.     Int16 theHotSpot = 0;
  714.     
  715.     if (::PtInRgn(inPoint, mCurrentTab->mMask))
  716.         {
  717.         theHotSpot = mValue;
  718.         }
  719.     else
  720.         {
  721.         CTabInstance* theTab;
  722.         LArrayIterator theIter(mTabs, LArrayIterator::from_Start);
  723.         while (theIter.Next(&theTab))
  724.             {
  725.             if (theTab == mCurrentTab)
  726.                 continue;
  727.                 
  728.             if (::PtInRgn(inPoint, theTab->mMask))
  729.                 {
  730.                 theHotSpot = mTabs.FetchIndexOf(&theTab);
  731.                 break;
  732.                 }
  733.             }
  734.         }
  735.         
  736.     return theHotSpot;
  737. }
  738.  
  739. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  740. //    Ñ    
  741. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  742.  
  743. Boolean CTabControl::PointInHotSpot(Point inPoint, Int16 inHotSpot)
  744. {
  745.     Assert_(mCurrentTab != NULL);
  746.     Boolean bInHotSpot = false;
  747.     // If the hot spot that we're checking is not the current tab
  748.     // then the tab is behind the current and is only partially
  749.     // exposed.  We need to mask out the hidden area.
  750.     if ((GetValue() != inHotSpot))
  751.         {
  752.         CTabInstance* theTab;
  753.         mTabs.FetchItemAt(inHotSpot, &theTab);
  754.         
  755.         StRegion theTempMask(theTab->mMask);
  756.         ::DiffRgn(theTempMask, mCurrentTab->mMask, theTempMask);
  757.         bInHotSpot = ::PtInRgn(inPoint, theTempMask);
  758.         }
  759.     else
  760.         bInHotSpot = ::PtInRgn(inPoint, mCurrentTab->mMask);
  761.  
  762.     return bInHotSpot;
  763. }
  764.  
  765.  
  766. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  767. //    Ñ    
  768. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  769.  
  770. void CTabControl::HotSpotAction(
  771.     Int16            inHotSpot,
  772.     Boolean         inCurrInside,
  773.     Boolean            inPrevInside)
  774. {
  775.     Assert_(mCurrentTab != NULL);
  776.  
  777.     // We only want to draw track feedback if the tab is not currently selected
  778.     if ((GetValue() != inHotSpot) && (inCurrInside != inPrevInside))
  779.     {
  780.         mTrackInside = inCurrInside;
  781.         
  782.         CTabInstance* theTab;
  783.         mTabs.FetchItemAt(inHotSpot, &theTab);
  784.         // This is not the proper way to draw feed back
  785.         // 1) it flickers badly. If you hold down the mouse button on a control you can see
  786.         //         the lines that make up the fram disappear;
  787.         // 2) If you click on a tab and then move the mouse out of the tab it doesn't
  788.         //         unhighlight the tab.
  789.          // DrawOneTab( theTab );
  790.     }
  791. }
  792.  
  793. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  794. //    Ñ    
  795. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  796.     
  797. void CTabControl::HotSpotResult(Int16 inHotSpot)
  798. {
  799.     // We got here because we successfully tracked,
  800.     // therefore changing value will undo tab hilighting
  801.     mTrackInside = false;
  802.     SetValue(inHotSpot);
  803. }
  804.  
  805. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  806. //    Ñ    
  807. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  808.  
  809. void CTabControl::SetValue(Int32 inValue)
  810. {
  811.     if ((inValue != mValue) ||  (mCurrentTab == NULL))
  812.         {
  813.         if (inValue < mMinValue) {        // Enforce min/max range
  814.             inValue = mMinValue;
  815.         } else if (inValue > mMaxValue) {
  816.             inValue = mMaxValue;
  817.         }
  818.         mTabs.FetchItemAt(inValue, &mCurrentTab);
  819.         SetValueMessage(mCurrentTab->mMessage);
  820.  
  821.         // setting the value broadcasts msg_TabSwitched with the tab's
  822.         // message in the ioParam
  823.         LControl::SetValue(inValue);  
  824.  
  825.         Draw(NULL);        // Draws offscreen if possible
  826.         }
  827. }
  828.  
  829. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  830. //    Ñ    
  831. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  832.  
  833. MessageT CTabControl::GetMessageForValue(Int32 inValue)
  834. {
  835.     MessageT theMessage = msg_Nothing;
  836.     if ((inValue >= mMinValue) && (inValue <= mMaxValue))
  837.         {
  838.         CTabInstance* theTab;
  839.         mTabs.FetchItemAt(inValue, &theTab);
  840.         theMessage = theTab->mMessage;
  841.         }
  842.         
  843.     return theMessage;
  844. }
  845.  
  846. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  847. //    Ñ    
  848. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  849.  
  850. void CTabControl::BroadcastValueMessage()
  851. {
  852.     if (mValueMessage != cmd_Nothing)
  853.         {
  854.         CTabInstance* theTab;        
  855.         mTabs.FetchItemAt(mValue, &theTab);
  856.         BroadcastMessage(msg_TabSwitched, &mValueMessage);
  857.         }
  858. }
  859.  
  860. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  861. //    Ñ    
  862. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  863.  
  864. void CTabControl::ResizeFrameBy(
  865.     Int16             inWidthDelta,
  866.     Int16            inHeightDelta,
  867.     Boolean            inRefresh)
  868. {
  869.     LControl::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
  870.     Recalc();
  871. }
  872.  
  873. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  874. //    Ñ    
  875. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  876.         
  877. void CTabControl::ActivateSelf(void)
  878. {
  879.     FocusDraw();
  880.     Draw(NULL);
  881.     
  882.     ::ValidRgn(mControlMask);
  883. }
  884.  
  885. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  886. //    Ñ    
  887. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  888.  
  889. void CTabControl::DeactivateSelf(void)
  890. {
  891.     FocusDraw();
  892.     Draw(NULL);
  893.     
  894.     ::ValidRgn(mControlMask);
  895. }
  896.         
  897. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  898. //    Ñ    
  899. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  900.  
  901. CTabInstance::CTabInstance()
  902. {
  903.     mMask = NULL;
  904. }
  905.  
  906. CTextTabInstance::CTextTabInstance(const STabDescriptor& inDesc)
  907. {
  908.     mMessage = inDesc.valueMessage;
  909.     mWidth = inDesc.width;
  910.     mTitle = inDesc.title;
  911.  
  912.     mMask = NULL;
  913. }
  914.  
  915. CTabInstance::~CTabInstance()
  916. {
  917.     if (mMask != NULL)
  918.         ::DisposeRgn(mMask);
  919. }
  920.  
  921. void CTextTabInstance::DrawTitle(CTabInstance* inCurrentTab, ResIDT inTitleTraitsID)
  922. {
  923.     if (mTitle.Length() >0)
  924.     {
  925.         StColorPenState::Normalize();
  926.  
  927.         TextTraitsH    theTraitsHandle = UTextTraits::LoadTextTraits(inTitleTraitsID);
  928.         Rect theFrame = mFrame;
  929.  
  930.         if (this == inCurrentTab)
  931.         {
  932.             (**theTraitsHandle).style |= bold;
  933.             ::OffsetRect(&theFrame, 0, 1);
  934.         }
  935.         
  936.         {
  937.             StHandleLocker theLocker((Handle)theTraitsHandle);
  938.             UTextTraits::SetPortTextTraits(*theTraitsHandle);
  939.             UGraphicGizmos::CenterStringInRect(mTitle, theFrame);
  940.         }
  941.         
  942.         ::ReleaseResource((Handle)theTraitsHandle);
  943.     }
  944. }
  945.  
  946.  
  947. CIconTabInstance::CIconTabInstance(const STabDescriptor& inDesc)
  948. {
  949.     mMessage = inDesc.valueMessage;
  950.     mWidth = 24; // Really should calc the size of the icon
  951.     ::StringToNum(inDesc.title, &mIconID);
  952.  
  953.     mMask = NULL;
  954. }
  955.  
  956. void CIconTabInstance::DrawTitle(CTabInstance* inCurrentTab, ResIDT /*inTitleTraitsID*/)
  957. {
  958.     StColorPenState::Normalize();
  959.  
  960.     Rect theFrame = mFrame;
  961.     theFrame.left += 4;//    And you thought the Instance was a hack
  962.     theFrame.right = theFrame.left + 16;
  963.     theFrame.top += 4;
  964.     theFrame.bottom = theFrame.top + 16;
  965.     IconTransformType transform = kTransformNone;
  966.     if (this == inCurrentTab)
  967.     {
  968.         ::OffsetRect(&theFrame, 0, 1);
  969.     }    
  970.     ::PlotIconID(&theFrame, kAlignAbsoluteCenter, transform, mIconID);
  971. }
  972.  
  973.  
  974.