/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #ifdef PowerPlant_PCH #include PowerPlant_PCH #endif #include "CMenuTable.h" #include #include #include #include #include #include #include //#include #include "CPrefsMediator.h" #pragma options align= packed struct CellData { MessageT message; Str255 label; }; #pragma options align=reset //---------------------------------------------------------------------------------------- CMenuTable::CMenuTable(LStream *inStream) : LTextHierTable(inStream) //, CQAPartnerTableMixin(this) //---------------------------------------------------------------------------------------- { *inStream >> mLeafTextTraits; *inStream >> mParentTextTraits; *inStream >> mFirstIndent; *inStream >> mLevelIndent; *inStream >> mMenuID; } //---------------------------------------------------------------------------------------- CMenuTable::~CMenuTable() //---------------------------------------------------------------------------------------- { } //----------------------------------- void CMenuTable::AddTableLabels( TableIndexT ¤tRow, ResIDT menuID, Boolean firstLevel) // Recursive. Adds table entries by using a hierarchical menu structure. //----------------------------------- { MenuHandle hMenu = nil; Int16** theMcmdH = nil; try { hMenu = ::GetMenu(menuID); ThrowIfResFail_(hMenu); short iItemCnt = ::CountMItems(hMenu); theMcmdH = (Int16**)::GetResource('Mcmd', menuID); ThrowIfResFail_(theMcmdH); if (**theMcmdH != iItemCnt) { ReleaseResource((Handle)theMcmdH); theMcmdH = nil; throw((OSErr)resNotFound); } StHandleLocker hl((Handle)theMcmdH); MessageT* messages = (MessageT *)(*theMcmdH + 1); // There does not seem to be a way to add a row that is at a higher // level than the one immediately preceding it. For this reason we // must make two pass through the labels. The first pass creates all of // the rows for a given level and the next pass adds the children. int menuItem; TableIndexT currentRowSaved = currentRow; for (menuItem = 1; menuItem <= iItemCnt; ++menuItem) { CellData theData; ::GetMenuItemText(hMenu, menuItem, theData.label); if (messages) theData.message = messages[menuItem - 1]; else theData.message = 0; short cmdChar; ::GetItemCmd(hMenu, menuItem, &cmdChar); Boolean hasSubMenus = (hMenuCmd == cmdChar); if (!firstLevel && (1 == menuItem)) { InsertChildRows( 1, currentRow++, &theData, sizeof(MessageT) + theData.label[0] + 1, hasSubMenus, false); } else { InsertSiblingRows( 1, currentRow++, &theData, sizeof(MessageT) + theData.label[0] + 1, hasSubMenus, false); } } currentRow = currentRowSaved; for (menuItem = 1; menuItem <= iItemCnt; ++menuItem) { short cmdChar; ::GetItemCmd(hMenu, menuItem, &cmdChar); Boolean hasSubMenus = (hMenuCmd == cmdChar); ++currentRow; if (hasSubMenus) { short markChar; ::GetItemMark(hMenu, menuItem, &markChar); // AddTableLabels(currentRow, markChar & 0x0F, false); AddTableLabels(currentRow, markChar, false); } } } catch(...) { if (hMenu) ReleaseResource((Handle)hMenu); if (theMcmdH) ReleaseResource((Handle)theMcmdH); throw; } if (hMenu) ReleaseResource((Handle)hMenu); if (theMcmdH) ReleaseResource((Handle)theMcmdH); } //---------------------------------------------------------------------------------------- void CMenuTable::FinishCreate() //---------------------------------------------------------------------------------------- { // geometry SDimension16 tableSize; GetFrameSize(tableSize); StTextState ts; UTextTraits::SetPortTextTraits(mParentTextTraits); FontInfo fi; ::GetFontInfo(&fi); Uint16 height = fi.ascent + fi.descent + fi.leading + 1; // the height should never be less than 12 height = height > 12? height: 12; LTableMonoGeometry *theGeometry = new LTableMonoGeometry( this, tableSize.width, fi.ascent + fi.descent + fi.leading + 1); SetTableGeometry(theGeometry); // selector LTableSingleSelector *theSelector = new LTableSingleSelector(this); SetTableSelector(theSelector); // storage LTableArrayStorage *theStorage = new LTableArrayStorage(this, (unsigned long)0); SetTableStorage(theStorage); // rows and cols InsertCols(1, 0, "", 0, false); TableIndexT currentRow = 0; AddTableLabels(currentRow, mMenuID); UnselectAllCells(); } //---------------------------------------------------------------------------------------- void CMenuTable::SelectionChanged() //---------------------------------------------------------------------------------------- { BroadcastMessage(msg_SelectionChanged, this); } //---------------------------------------------------------------------------------------- MessageT CMenuTable::GetSelectedMessage() //---------------------------------------------------------------------------------------- { MessageT result = 0; STableCell theCell = GetFirstSelectedCell(); // we have only one CellData theData; unsigned long theSize = sizeof(theData); if (theCell.row && theCell.col) { TableIndexT index; CellToIndex(theCell, index); index = GetWideOpenIndex(index); STableCell expandedCell; IndexToCell(index, expandedCell); GetCellData(expandedCell, &theData, theSize); if (theSize > sizeof(theData.message)) { result = theData.message; } } return result; } //---------------------------------------------------------------------------------------- TableIndexT CMenuTable::FindMessage( MessageT message ) // Returns Wide Open index //---------------------------------------------------------------------------------------- { TableIndexT index = 0; CellData cellData; STableCell cell(0,0); unsigned long theSize = sizeof(cellData); TableIndexT numberRows, numberCols; GetWideOpenTableSize( numberRows, numberCols ) ; for ( TableIndexT i = 1; i<= numberRows; i++ ) { IndexToCell( i, cell ); GetCellData( cell , &cellData, theSize ); if ( cellData.message == message ) { index = i; break; } } return index; } //---------------------------------------------------------------------------------------- void CMenuTable::DrawCell( const STableCell &inCell, const Rect &inLocalRect) //---------------------------------------------------------------------------------------- { TableIndexT woRow = mCollapsableTree->GetWideOpenIndex(inCell.row); DrawDropFlag(inCell, woRow); STableCell woCell(woRow, inCell.col); CellData cellData; Uint32 dataSize = sizeof(cellData); GetCellData(woCell, &cellData, dataSize); ResIDT textTraitsID = mLeafTextTraits; if (mCollapsableTree->IsCollapsable(woRow)) { textTraitsID = mParentTextTraits; } UTextTraits::SetPortTextTraits(textTraitsID); Uint32 nestingLevel = mCollapsableTree->GetNestingLevel(woRow); FontInfo fi; ::GetFontInfo(&fi); Int16 height = inLocalRect.top + (inLocalRect.bottom - inLocalRect.top) / 2 + fi.ascent - ((fi.ascent + fi.descent) / 2); MoveTo(inLocalRect.left + mFirstIndent + nestingLevel * mLevelIndent, height); DrawString(cellData.label); } //---------------------------------------------------------------------------------------- void CMenuTable::GetHiliteRgn(RgnHandle ioHiliteRgn) // Pass back a Region containing the frames of all selected cells which // are within the visible rectangle of the Table // // Caller must allocate space for the region //---------------------------------------------------------------------------------------- { ::SetEmptyRgn(ioHiliteRgn); // Assume no visible selection Rect visRect; GetRevealedRect(visRect); // Check if Table is revealed if (!::EmptyRect(&visRect)) { PortToLocalPoint(topLeft(visRect)); PortToLocalPoint(botRight(visRect)); STableCell topLeftCell, botRightCell; FetchIntersectingCells(visRect, topLeftCell, botRightCell); RgnHandle cellRgn = ::NewRgn(); STableCell cell; // Loop thru all cells for (cell.row = topLeftCell.row; cell.row <= botRightCell.row; cell.row++) { for (cell.col = topLeftCell.col; cell.col <= botRightCell.col; cell.col++) { if (CellIsSelected(cell)) { Rect cellRect; GetLocalCellRect(cell, cellRect); cellRect.left += (mFirstIndent - 1); ::RectRgn(cellRgn, &cellRect); ::UnionRgn(ioHiliteRgn, cellRgn, ioHiliteRgn); } } } ::DisposeRgn(cellRgn); } } //---------------------------------------------------------------------------------------- void CMenuTable::HiliteSelection( Boolean inActively, Boolean inHilite) // Draw or undraw hiliting for the current selection in either the // active or inactive state //---------------------------------------------------------------------------------------- { STableCell theCell; while (GetNextSelectedCell(theCell)) { if (inActively) { HiliteCellActively(theCell, inHilite); } else { HiliteCellInactively(theCell, inHilite); } } } //---------------------------------------------------------------------------------------- void CMenuTable::HiliteCellActively(const STableCell &inCell, Boolean /* inHilite */) //---------------------------------------------------------------------------------------- { Rect cellFrame; if (GetLocalCellRect(inCell, cellFrame) && FocusExposed()) { StColorPenState saveColorPen; // Preserve color & pen state StColorPenState::Normalize(); UDrawingUtils::SetHiliteModeOn(); TableIndexT woRow = mCollapsableTree->GetWideOpenIndex(inCell.row); Uint32 nestingLevel = mCollapsableTree->GetNestingLevel(woRow); cellFrame.left += (mFirstIndent +nestingLevel*mLevelIndent ); ::InvertRect(&cellFrame); } } //---------------------------------------------------------------------------------------- void CMenuTable::HiliteCellInactively(const STableCell &inCell, Boolean /* inHilite */) //---------------------------------------------------------------------------------------- { Rect cellFrame; if (GetLocalCellRect(inCell, cellFrame) && FocusExposed()) { StColorPenState saveColorPen; // Preserve color & pen state StColorPenState::Normalize(); TableIndexT woRow = mCollapsableTree->GetWideOpenIndex(inCell.row); Uint32 nestingLevel = mCollapsableTree->GetNestingLevel(woRow); cellFrame.left += (mFirstIndent +nestingLevel*mLevelIndent ); UDrawingUtils::SetHiliteModeOn(); ::PenMode(srcXor); ::FrameRect(&cellFrame); } } //---------------------------------------------------------------------------------------- void CMenuTable::ClickSelf(const SMouseDownEvent &inMouseDown) //---------------------------------------------------------------------------------------- { STableCell hitCell; SPoint32 imagePt; LocalToImagePoint(inMouseDown.whereLocal, imagePt); if (GetCellHitBy(imagePt, hitCell)) { // Before calling CPrefsPaneManager::CanSwitch() we should check to see // if the click is on a different cell. (No point in calling CanSwitch() // if we aren't going to switch.) Boolean switchAllowed = true; if (hitCell != GetFirstSelectedCell()) { switchAllowed = CPrefsMediator::CanSwitch(); } if (switchAllowed) { // Click is inside hitCell // Check if click is inside DropFlag TableIndexT woRow = mCollapsableTree->GetWideOpenIndex(hitCell.row); Rect flagRect; CalcCellFlagRect(hitCell, flagRect); if (mCollapsableTree->IsCollapsable(woRow) && ::PtInRect(inMouseDown.whereLocal, &flagRect)) { // Click is inside DropFlag FocusDraw(); Boolean expanded = mCollapsableTree->IsExpanded(woRow); if (LDropFlag::TrackClick(flagRect, inMouseDown.whereLocal, expanded)) { // Mouse released inside DropFlag // so toggle the Row if (inMouseDown.macEvent.modifiers & optionKey) { // OptionKey down means to do // a deep collapse/expand if (expanded) { DeepCollapseRow(woRow); } else { DeepExpandRow(woRow); } } else { // Shallow collapse/expand if (expanded) { CollapseRow(woRow); } else { ExpandRow(woRow); } } } } if (ClickSelect(hitCell, inMouseDown)) { // Click outside of the DropFlag ClickCell(hitCell, inMouseDown); } } // else don't allow the selection to change } else { // Click is outside of any Cell UnselectAllCells(); } } #pragma mark - #if defined(QAP_BUILD) //----------------------------------- void CMenuTable::QapGetListInfo(PQAPLISTINFO pInfo) //----------------------------------- { TableIndexT outRows, outCols, lcv; if (pInfo == nil) return; GetWideOpenTableSize(outRows, outCols); for (lcv = 0; lcv < outRows; lcv++) { if (IsCollapsable(lcv) && !IsExpanded(lcv)) { ExpandRow(lcv); } } // fetch vertical scrollbar Macintosh control ControlHandle macVScroll = NULL; LScroller *myScroller = dynamic_cast(GetSuperView()); if (myScroller != NULL) { if (myScroller->GetVScrollbar() != NULL) macVScroll = myScroller->GetVScrollbar()->GetMacControl(); } pInfo->itemCount = (short)outRows; pInfo->topIndex = 0; pInfo->itemHeight = GetRowHeight(0); pInfo->visibleCount = outRows; pInfo->vScroll = macVScroll; pInfo->isMultiSel = false; pInfo->isExtendSel = false; pInfo->hasText = true; } //----------------------------------- Ptr CMenuTable::QapAddCellToBuf(Ptr pBuf, Ptr pLimit, const STableCell& sTblCell) //----------------------------------- { char str[256]; short len = 0; CellData theData; UInt32 dataSize = sizeof(theData); GetCellData(sTblCell, (void *)&theData, dataSize); strncpy(str, (const char *)&theData.label[1], (short)theData.label[0]); str[(short)theData.label[0]] = '\0'; len = strlen(str) + 1; if (pBuf + sizeof(short) + len >= pLimit) return NULL; *(unsigned short *)pBuf = sTblCell.row - 1; if (CellIsSelected(sTblCell)) *(unsigned short *)pBuf |= 0x8000; pBuf += sizeof(short); strcpy(pBuf, str); pBuf += len; return pBuf; } #endif //QAP_BUILD