home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / PowerPlant / Multi-Panel Dialogs 1.1 / MPD Sources / CMPDPanelSelectTable.cp < prev    next >
Encoding:
Text File  |  1996-09-25  |  17.4 KB  |  534 lines  |  [TEXT/R*ch]

  1. // ===========================================================================
  2. //    File:                        CMPDPanelSelectTable.cp
  3. // Version:                    1.0 - Feb 1, 1996
  4. //    Author:                    Mike Shields (mshields@inconnect.com)
  5. //                            
  6. //    Copyright ©1996 Mike Shields. All rights reserved.
  7. //    I hereby grant users of CMPDPanelSelectTable permission to use it (or any modified 
  8. //    version of it) in applications (or any other type of Macintosh software 
  9. //    like extensions -- freeware, shareware, commercial, or other) for free, 
  10. //    subject to the terms that:
  11. //
  12. //        (1)  This agreement is non-exclusive.
  13. //
  14. //        (2)  I, Mike Shields, retain the copyright to the original source code.
  15. //
  16. //    These two items are the only required conditions for use. However, I do have 
  17. //    an additional request. Note, however, that this is only a request, and 
  18. //    that it is not a required condition for use of this code.
  19. //
  20. //        (1) That I be given credit for CMPDPanelSelectTable code in the copyrights or 
  21. //            acknowledgements section of your manual or other appropriate documentation.
  22. //
  23. //
  24. //    I would like to repeat that this last item is only a request. You are prefectly 
  25. //    free to choose not to do any or all of them.
  26. //    
  27. //        This source code is distributed in the hope that it will be useful,
  28. //        but WITHOUT ANY WARRANTY; without even the implied warranty of
  29. //        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  30. // ===========================================================================
  31. //    CMPDPanelSelectTable.h        <- double-click + Command-D to see class declaration
  32. //
  33. // Displays a scrolling list of icons and title strings. Also acts 
  34. // like a control and broadcasts a hit message when an item changes.
  35.  
  36. #include "CMPDPanelSelectTable.h"
  37.  
  38. #include <LTableMonoGeometry.h>
  39. #include <LTableSingleSelector.h>
  40. #include <LTableArrayStorage.h>
  41.  
  42. #include <LStream.h>
  43. #include <LString.h>
  44. #include <UTextTraits.h>
  45. #include <UDrawingUtils.h>
  46. #include <PP_Messages.h>
  47. #include <UKeyFilters.h>
  48. #include <PP_KeyCodes.h>
  49.  
  50. #ifndef __TEXTEDIT__
  51. #include <TextEdit.h>
  52. #endif
  53.  
  54. #ifndef __LOWMEM__
  55. #include <LowMem.h>
  56. #endif
  57.  
  58. #ifndef __ICONS__
  59. #include <Icons.h>
  60. #endif
  61.  
  62. const short kMinimumRowHeight    = 50;
  63.  
  64. #pragma mark === Construction & Destruction ===
  65.  
  66. //----------------------------------------------------------------------------------------
  67. // CMPDPanelSelectTable::CreateFromStream 
  68. //----------------------------------------------------------------------------------------
  69. // Static function registered with URegistrar to create a MPDPanelSelectTable from the data 
  70. // in a stream
  71. CMPDPanelSelectTable* CMPDPanelSelectTable::CreateFromStream(LStream *inStream)
  72. {
  73.     return (new CMPDPanelSelectTable(inStream));
  74. }
  75.  
  76. //----------------------------------------------------------------------------------------
  77. // CMPDPanelSelectTable::CMPDPanelSelectTable 
  78. //----------------------------------------------------------------------------------------
  79. // Default Contructor
  80. CMPDPanelSelectTable::CMPDPanelSelectTable()
  81.     : mTextTraitsID(0)
  82. {
  83.     if ( mSuperCommander != nil ) 
  84.     {
  85.         mSuperCommander->SetLatentSub(this);
  86.     }
  87.     mUseDragSelect = true;
  88. }
  89.  
  90. //----------------------------------------------------------------------------------------
  91. // CMPDPanelSelectTable::CMPDPanelSelectTable 
  92. //----------------------------------------------------------------------------------------
  93. // Construct from input parameters
  94. CMPDPanelSelectTable::CMPDPanelSelectTable(const SPaneInfo &inPaneInfo,
  95.                                                     const SViewInfo &inViewInfo,
  96.                                                     ResIDT inTextTraitsID)
  97.     : LTableView(inPaneInfo, inViewInfo), mTextTraitsID(inTextTraitsID)
  98. {
  99.     if ( mSuperCommander != nil ) 
  100.     {
  101.         mSuperCommander->SetLatentSub(this);
  102.     }
  103.  
  104.     SetTableGeometry(new LTableMonoGeometry(this, mFrameSize.width, kMinimumRowHeight));
  105.     SetTableSelector(new LTableSingleSelector(this));
  106.     SetTableStorage(new LTableArrayStorage(this, sizeof(SIconTableRec)));
  107.  
  108.     mRows = 0;
  109.     mCols = 1;
  110.     mUseDragSelect = true;
  111. }
  112.  
  113. //----------------------------------------------------------------------------------------
  114. // CMPDPanelSelectTable::CMPDPanelSelectTable 
  115. //----------------------------------------------------------------------------------------
  116. // Construct from the data in a Stream
  117. CMPDPanelSelectTable::CMPDPanelSelectTable(LStream *inStream)
  118.     : LTableView(inStream)
  119. {
  120.     Int16        rowHeight;
  121.     inStream->ReadData(&rowHeight, sizeof(Int16));
  122.     SignalIf_(rowHeight < kMinimumRowHeight);
  123.     
  124.     inStream->ReadData(&mTextTraitsID, sizeof(ResIDT));
  125.     
  126.     if ( mSuperCommander != nil ) 
  127.     {
  128.         mSuperCommander->SetLatentSub(this);
  129.     }
  130.     
  131.     SetTableGeometry(new LTableMonoGeometry(this, mFrameSize.width, rowHeight));
  132.     SetTableSelector(new LTableSingleSelector(this));
  133.     SetTableStorage(new LTableArrayStorage(this, sizeof(SIconTableRec)));
  134.  
  135.     mRows = 0;
  136.     mCols = 1;
  137.     mUseDragSelect = true;
  138. }
  139.  
  140. //----------------------------------------------------------------------------------------
  141. // CMPDPanelSelectTable::~CMPDPanelSelectTable 
  142. //----------------------------------------------------------------------------------------
  143. // Destructor
  144. CMPDPanelSelectTable::~CMPDPanelSelectTable()
  145. {
  146. }
  147.  
  148. #pragma mark === PanelSelect Management ===
  149. //----------------------------------------------------------------------------------------
  150. // CMPDPanelSelectTable::InsertPanelIDAt 
  151. //----------------------------------------------------------------------------------------
  152. // Insert data into the MPDPanelSelectTable describing a panel identifier to be displayed 
  153. // in the control
  154. void CMPDPanelSelectTable::InsertPanelIDs(MPDPtr inPanelIDData)
  155. {
  156.     SIconTableRec    rowData;
  157.  
  158.     for ( Int16 i = 0; i < inPanelIDData->numItems; i++ )
  159.     {
  160.         rowData.iconID = inPanelIDData->MPDList[i].iconID;
  161.         LString::CopyPStr(inPanelIDData->MPDList[i].name, rowData.name, sizeof(rowData.name));
  162.     
  163.         InsertRows(1, inPanelIDData->numItems, &rowData, sizeof(SIconTableRec), false);
  164.     }
  165. }
  166.  
  167. //----------------------------------------------------------------------------------------
  168. // CMPDPanelSelectTable::SelectPanelID 
  169. //----------------------------------------------------------------------------------------
  170. // Select a specific PanelID
  171. void CMPDPanelSelectTable::SelectPanelID(PanelIDIndexT inPanelID)
  172. {
  173.     STableCell    theSelection(inPanelID, 1);
  174.     
  175.     ScrollCellIntoFrame(theSelection);
  176.     SelectCell(theSelection);
  177. }
  178.  
  179. //----------------------------------------------------------------------------------------
  180. // CMPDPanelSelectTable::GetCurrentPanelID 
  181. //----------------------------------------------------------------------------------------
  182. // Return the index of the currently selected PanelID
  183. PanelIDIndexT CMPDPanelSelectTable::GetCurrentPanelID(void) const
  184. {
  185.     STableCell    theSelection;
  186.     
  187.     if ( GetNextSelectedCell(theSelection) )
  188.         return theSelection.row;
  189.     else
  190.         return 0;
  191. }
  192.  
  193. #pragma mark === Clicking & Drawing ===
  194. //----------------------------------------------------------------------------------------
  195. // CMPDPanelSelectTable::ClickSelf 
  196. //----------------------------------------------------------------------------------------
  197. //    Handle a mouse click within a MPDPanelSelectTable. We want to make this object the target
  198. // if switching the target can be allowed.
  199. void CMPDPanelSelectTable::ClickSelf(const SMouseDownEvent &inMouseDown)
  200. {
  201.     STableCell    hitCell;
  202.     SPoint32        imagePt;
  203.     
  204.     LocalToImagePoint(inMouseDown.whereLocal, imagePt);
  205.     
  206.     if ( SwitchTarget(this) )
  207.         if ( GetCellHitBy(imagePt, hitCell) )    // Only pass the click on up if we're clicking on a cell
  208.             LTableView::ClickSelf(inMouseDown);
  209. }
  210.  
  211. //----------------------------------------------------------------------------------------
  212. // CMPDPanelSelectTable::DrawCell 
  213. //----------------------------------------------------------------------------------------
  214. // draw a specific cell.
  215. void CMPDPanelSelectTable::DrawCell(const STableCell &inCell,
  216.                                                         const Rect &inLocalRect)
  217. {
  218.     DrawCellSelf(inCell, inLocalRect, CellIsSelected(inCell));
  219. }
  220.  
  221. //----------------------------------------------------------------------------------------
  222. // CMPDPanelSelectTable::DrawCellSelf 
  223. //----------------------------------------------------------------------------------------
  224. // draw a specific cell along with the appropriate hilighting. This is used by DrawCell, 
  225. // HiliteCellActively, and HiliteCellInactively
  226. void CMPDPanelSelectTable::DrawCellSelf(const STableCell &inCell, const Rect &inLocalRect,
  227.                                                 Boolean inHilite)
  228. {
  229. #define kIconHeight                32
  230. #define kIconNameGap                2
  231. #define kNameHeight                12
  232. #define kNameWidthSlop            4
  233. #define kPanelIDTotalHeight    (kIconHeight + kIconNameGap + kNameHeight)
  234.  
  235.     SIconTableRec    iconAndName;
  236.     Uint32            dataSize = sizeof(SIconTableRec);
  237.     Rect                iconRect;
  238.     Rect                textRect;
  239.     LStr255            iconName;
  240.     
  241.     // get the data for the cell we're about to draw.
  242.     GetCellData(inCell, &iconAndName, dataSize);
  243.     iconName = iconAndName.name;
  244.     
  245.     // Draw the icon with the correct hilite on it.
  246.     iconRect.left = inLocalRect.left + ((inLocalRect.right - inLocalRect.left - kIconHeight) / 2);
  247.     iconRect.right = iconRect.left + kIconHeight;
  248.     iconRect.top = inLocalRect.top + ((inLocalRect.bottom - inLocalRect.top - kPanelIDTotalHeight) / 4);
  249.     iconRect.bottom = iconRect.top + kIconHeight;
  250.     if ( inHilite )
  251.         ::PlotIconID(&iconRect, atNone, ttSelected, iconAndName.iconID);
  252.     else
  253.         ::PlotIconID(&iconRect, atNone, ttNone, iconAndName.iconID);
  254.  
  255.     // first check to see if the string is too long. If so, change over to condensed text. 
  256.     // This might make it it.
  257.     UTextTraits::SetPortTextTraits(mTextTraitsID);
  258.     short textWidth = ::TextWidth((Ptr)&iconName[1], 0, iconName.Length());
  259.     if ( textWidth > (inLocalRect.right - inLocalRect.left) )
  260.     {
  261.         ::TextFace(condense);
  262.         textWidth = ::TextWidth((Ptr)&iconName[1], 0, iconName.Length());
  263.     }
  264.     
  265.     // We'll call TruncString no matter what because it will truncate it if it still needs to be
  266.     // otherwise it'll leave it alone.
  267.     ::TruncString(inLocalRect.right - inLocalRect.left, iconName, truncMiddle);
  268.  
  269.     textRect.left = inLocalRect.left + ((inLocalRect.right - inLocalRect.left - (textWidth + kNameWidthSlop)) / 2);
  270.     textRect.right = textRect.left + textWidth + kNameWidthSlop;
  271.     textRect.top = iconRect.bottom + kIconNameGap;
  272.     textRect.bottom = textRect.top + kNameHeight;
  273.     UTextDrawing::DrawWithJustification((Ptr)&iconName[1], iconName.Length(), 
  274.                                                     textRect, teCenter);
  275.  
  276.     if ( inHilite ) 
  277.     {
  278.         LMSetHiliteMode(LMGetHiliteMode() ^ (1 << hiliteBit));
  279.           ::InvertRect(&textRect);
  280.     }
  281. }
  282.  
  283. #pragma mark === Hiliting ===
  284. //----------------------------------------------------------------------------------------
  285. // CMPDPanelSelectTable::HiliteCellActively 
  286. //----------------------------------------------------------------------------------------
  287. //    Draw or undraw active hiliting for a Cell. This is the same no matter what.
  288. void CMPDPanelSelectTable::HiliteSelection(Boolean inActively, Boolean inHilite)
  289. {
  290.     STableCell    theCell;
  291.     
  292.     while ( GetNextSelectedCell(theCell) ) 
  293.     {
  294.         if (inActively) 
  295.             HiliteCellActively(theCell, inHilite);
  296.         else 
  297.             HiliteCellInactively(theCell, inHilite);
  298.     }
  299. }
  300.  
  301. //----------------------------------------------------------------------------------------
  302. // CMPDPanelSelectTable::HiliteCellActively 
  303. //----------------------------------------------------------------------------------------
  304. //    Draw or undraw active hiliting for a Cell. This is the same no matter what.
  305. void CMPDPanelSelectTable::HiliteCellActively(const STableCell &inCell, Boolean inHilite)
  306. {
  307.     Rect    cellFrame;
  308.     if ( GetLocalCellRect(inCell, cellFrame) && FocusExposed() ) 
  309.     {
  310.         ApplyForeAndBackColors();
  311.         ::EraseRect(&cellFrame);
  312.         DrawCellSelf(inCell, cellFrame, inHilite);
  313.     }
  314. }
  315.  
  316. //----------------------------------------------------------------------------------------
  317. // CMPDPanelSelectTable::HiliteCellInactively 
  318. //----------------------------------------------------------------------------------------
  319. //    Draw or undraw inactive hiliting for a Cell. This is the same no matter what.
  320. void CMPDPanelSelectTable::HiliteCellInactively(const STableCell &inCell, Boolean inHilite)
  321. {
  322.     Rect    cellFrame;
  323.     if ( GetLocalCellRect(inCell, cellFrame) && FocusExposed() ) 
  324.     {
  325.         ApplyForeAndBackColors();
  326.         ::EraseRect(&cellFrame);
  327.         DrawCellSelf(inCell, cellFrame, inHilite);
  328.     }
  329. }
  330.  
  331. #pragma mark === Selection ===
  332. //---------------------------------------------------------------------------
  333. // CMPDPanelSelectTable::SelectionChanged
  334. //---------------------------------------------------------------------------
  335. //    Broadcast the fact that the table selection has changed
  336. void CMPDPanelSelectTable::SelectionChanged()
  337. {
  338.     ReportPanelIDChanged();
  339. }
  340.  
  341. #pragma mark === Command Handling ===
  342. //---------------------------------------------------------------------------
  343. // CMPDPanelSelectTable::ObeyCommand
  344. //---------------------------------------------------------------------------
  345. //    Handle the msg_TabSelect command to switch ourselves to be the target
  346. Boolean CMPDPanelSelectTable::ObeyCommand(CommandT inCommand, void* ioParam)
  347. {
  348.     Boolean        cmdHandled = true;
  349.     
  350.     switch (inCommand) 
  351.     {
  352.         case msg_TabSelect:
  353.             if ( !IsEnabled() ) 
  354.             {
  355.                 cmdHandled = false;
  356.             }
  357.             break;
  358.             
  359.         default:
  360.             cmdHandled = LCommander::ObeyCommand(inCommand, ioParam);
  361.             break;
  362.     }
  363.     
  364.     return cmdHandled;
  365. }
  366.  
  367. //---------------------------------------------------------------------------
  368. // CMPDPanelSelectTable::HandleKeyPress
  369. //---------------------------------------------------------------------------
  370. //    Supports keyboard navigation
  371. Boolean CMPDPanelSelectTable::HandleKeyPress(const EventRecord &inKeyEvent)
  372. {
  373.     Boolean    keyHandled = true;
  374.     Char16    theKey = inKeyEvent.message & charCodeMask;
  375.     
  376.     FocusDraw();
  377.  
  378.     if ( UKeyFilters::IsNavigationKey(theKey) ) 
  379.     {
  380.         DoNavigationKey(inKeyEvent);
  381.     }
  382.     else
  383.     {
  384.         keyHandled = LCommander::HandleKeyPress(inKeyEvent);
  385.     }
  386.             
  387.     return keyHandled;
  388. }
  389.  
  390. //---------------------------------------------------------------------------
  391. // CMPDPanelSelectTable::DoNavigationKey
  392. //---------------------------------------------------------------------------
  393. //    Implements keyboard navigation by supporting selection change using
  394. //    the arrow keys, page up, page down, home, and end
  395. void CMPDPanelSelectTable::DoNavigationKey(const EventRecord&inKeyEvent)
  396. {
  397.     char            theKey = inKeyEvent.message & charCodeMask;
  398.     Boolean        cmdKeyDown = (inKeyEvent.modifiers & cmdKey) != 0;
  399.     STableCell    theSelection;
  400.     Boolean        cellIsSelected = GetNextSelectedCell(theSelection);
  401.     
  402.     switch ( theKey ) 
  403.     {
  404.         case char_UpArrow:
  405.         case char_LeftArrow:
  406.             if ( cellIsSelected )
  407.             {
  408.                 // Select cell one above the first
  409.                 //   selected cell
  410.                 if ( theSelection.row > 1 ) 
  411.                 {
  412.                     theSelection.row -= 1;
  413.                     SelectCell(theSelection);
  414.                     ScrollCellIntoFrame(theSelection);
  415.                 }
  416.             }
  417.             else
  418.             {
  419.                 theSelection.SetCell(1, 1);
  420.                 SelectCell(theSelection);
  421.                 ScrollCellIntoFrame(theSelection);
  422.             }
  423.             break;
  424.  
  425.         case char_DownArrow:
  426.         case char_RightArrow:
  427.             if ( cellIsSelected )
  428.             {
  429.                 // Select cell one after the first
  430.                 //   selected cell
  431.                 if ( theSelection.row < mRows ) 
  432.                 {
  433.                     theSelection.row += 1;
  434.                     SelectCell(theSelection);
  435.                     ScrollCellIntoFrame(theSelection);
  436.                 }
  437.             }
  438.             else
  439.             {
  440.                 theSelection.SetCell(1, 1);
  441.                 SelectCell(theSelection);
  442.                 ScrollCellIntoFrame(theSelection);
  443.             }
  444.             break;
  445.             
  446.         case char_Home:
  447.             ScrollPinnedImageBy(0, -mImageSize.height, true);
  448.             break;
  449.  
  450.         case char_End:
  451.             ScrollPinnedImageBy(0, mImageSize.height, true);
  452.             break;
  453.             
  454.         case char_PageUp:
  455.         case char_PageDown: 
  456.         {
  457.             Rect        frame;
  458.             Uint16    cellHeight;
  459.             Uint32    scrollValue;
  460.             Uint16    numOfFullVisibleCells;
  461.             
  462.             CalcLocalFrameRect(frame);
  463.             cellHeight = GetRowHeight(1);
  464.             numOfFullVisibleCells = (frame.bottom - frame.top) % cellHeight;
  465.             scrollValue = numOfFullVisibleCells * cellHeight;
  466.             
  467.             ScrollPinnedImageBy(0, (theKey == char_PageUp) ? -scrollValue : scrollValue, true);
  468.             break;
  469.         }
  470.     }
  471. }    
  472.  
  473. #pragma mark === Accessing Cells ===
  474. //---------------------------------------------------------------------------
  475. //    CMPDPanelSelectTable::ScrollCellIntoFrame
  476. //---------------------------------------------------------------------------
  477. //    Scroll the TableView as little as possible to move the specified Cell
  478. //    so that it's entirely within the Frame of the TableView
  479. void CMPDPanelSelectTable::ScrollCellIntoFrame(const STableCell &inCell)
  480. {
  481.     SPoint32    cellTopLeft;
  482.     SPoint32    cellBotRight;
  483.     mTableGeometry->GetImageCellBounds(inCell, cellTopLeft.h, cellTopLeft.v,
  484.                                                     cellBotRight.h, cellBotRight.v);
  485.                             
  486.     if ( ImagePointIsInFrame(cellTopLeft.h, cellTopLeft.v) &&
  487.         ImagePointIsInFrame(cellBotRight.h, cellBotRight.v) ) 
  488.     {
  489.         return;                        // Cell is already within Frame
  490.     }
  491.     
  492.     Rect        frame;
  493.     SPoint32    frameTopLeft;
  494.     SPoint32    frameBotRight;
  495.     
  496.     CalcLocalFrameRect(frame);
  497.  
  498.     LocalToImagePoint(topLeft(frame), frameTopLeft);
  499.     LocalToImagePoint(botRight(frame), frameBotRight);
  500.     
  501.     if ( frameBotRight.v < cellBotRight.v )
  502.     {
  503.         // Cell is off the bottom of the frame
  504.         ScrollPinnedImageBy(0, -(frameBotRight.v - cellBotRight.v), true);
  505.     }
  506.     else if ( frameTopLeft.v > cellTopLeft.v )
  507.     {
  508.         // Cell is off the top of the frame
  509.         ScrollPinnedImageBy(0, -(frameTopLeft.v - cellTopLeft.v), true);
  510.     }
  511. }
  512.  
  513. #pragma mark === Targeting Control ===
  514. //---------------------------------------------------------------------------
  515. // CMPDPanelSelectTable::BeTarget
  516. //---------------------------------------------------------------------------
  517. // Tell our TargeterBox that we are now the target.
  518. void CMPDPanelSelectTable::BeTarget()
  519. {
  520.     LCommander::BeTarget();
  521.     ShowFocus();
  522. }
  523.  
  524. //---------------------------------------------------------------------------
  525. // CMPDPanelSelectTable::DontBeTarget
  526. //---------------------------------------------------------------------------
  527. // Tell our TargeterBox that we are no longer the target.
  528. void CMPDPanelSelectTable::DontBeTarget()
  529. {
  530.     LCommander::DontBeTarget();
  531.     HideFocus();
  532. }
  533.  
  534.