/*----------------------------------------------------------------------------- StdPopup Written 1994 Netscape Communications Corporation Portions derived from MacApp, Copyright © 1984-1994 Apple Computer, Inc. All rights reserved. -----------------------------------------------------------------------------*/ // primary header #include "PopupBox.h" // local libraries // cross-platform libraries #include "xpassert.h" #include "xp_trace.h" // PowerPlant #include #include #include // Macintosh headers #include #include #include #include #include // ANSI headers #include #include #include #include "UFontSwitcher.h" #include "UUTF8TextHandler.h" #include "UPropFontSwitcher.h" #include "UCustomizePopUp.h" #include "LCustomizeMenu.h" //----------------------------------------------------------------------------- // random stuff //----------------------------------------------------------------------------- #define SETMODRECT(DEST,SOURCE,TOP,LEFT,BOTTOM,RIGHT) \ SetRect (&(DEST), (SOURCE).LEFT, (SOURCE).TOP, (SOURCE).RIGHT, (SOURCE).BOTTOM) #ifndef GetMenuProc #define GetMenuProc(menu) (*((Handle *) ((*((Ptr *) (menu))) + 0x06))) #endif //----------------------------------------------------------------------------- // Discrete List Box //----------------------------------------------------------------------------- const Int16 fontNumber_Unknown = -1; StdPopup::StdPopup (CGAPopupMenu * target) : LAttachment () { ThrowIfNil_(fTarget = target); fTarget->SetNeedCustomDrawFlag(NeedCustomPopup()); mExecuteHost = false; fMenu = nil; fDirty = true; } StdPopup::~StdPopup () { if (fMenu) DisposeMenu (fMenu); } // // definition // short StdPopup::GetCount () { return 0; } CStr255 StdPopup::GetText (short item) { char buffer [20]; sprintf (buffer, "%hi", item); return buffer; } // // interface // const int tlo = 18; // offset of text from left side of widget const int tls = 23; // offset from right side of widget to left side of triangle icon Point StdPopup::CalcTargetFrame (short & baseline) { SyncMenu (fTarget->GetMacMenuH()); Point size; size.v = /* text */ 16 + /* border */ 3; size.h = CalcMaxWidth (fTarget->GetMacMenuH()) + tls; StColorPenState saveColorPenState; StTextState saveTextState; saveColorPenState.Normalize(); saveTextState.Normalize(); FontInfo fontInfo; GetFontInfo (&fontInfo); baseline = 1 + fontInfo.ascent; size.v = fontInfo.ascent+fontInfo.descent+fontInfo.leading+ 2; return size; } void StdPopup::DirtyMenu () { fDirty = true; } // // internal // short StdPopup::CalcMaxWidth (MenuHandle aquiredMenu) { if (1 || fDirty) { Rect menuRect; Point hitPt = {0,0}; short whichItem; MenuDefUPP * menuProc = (MenuDefUPP*) (*aquiredMenu)->menuProc; SInt8 theState = HGetState((*aquiredMenu)->menuProc); HLock((*aquiredMenu)->menuProc); CallMenuDefProc (*menuProc, mSizeMsg, aquiredMenu, &menuRect, hitPt, &whichItem); HSetState((*aquiredMenu)->menuProc, theState); } return (*aquiredMenu)->menuWidth; } void StdPopup::DrawTruncTextBox (CStr255 text, const Rect& box) { /* Truncates the text before drawing. Does not word wrap. */ FontInfo fontInfo; GetFontInfo (&fontInfo); MoveTo (box.left, box.bottom - fontInfo.descent -1); TruncString (box.right - box.left, text, truncEnd); DrawString (text); } void StdPopup::DrawWidget (MenuHandle aquiredMenu, const Rect & widgetFrame) { StColorPenState saveColorPenState; StTextState saveTextState; saveColorPenState.Normalize(); saveTextState.Normalize(); if (GetTextTraits() != fontNumber_Unknown) UTextTraits::SetPortTextTraits(GetTextTraits()); Rect r; SETMODRECT(r,widgetFrame,top+1,left+1,bottom-2,right-2); EraseRect (&r); MoveTo (widgetFrame.left + 3, widgetFrame.bottom - 1); LineTo (widgetFrame.right -1, widgetFrame.bottom - 1); MoveTo (widgetFrame.right -1, widgetFrame.top + 3); LineTo (widgetFrame.right -1, widgetFrame.bottom - 1); SETMODRECT(r,widgetFrame,top,left,bottom-1,right-1); FrameRect (&r); SETMODRECT(r,widgetFrame,top-1,right-tls,top-1+16,right-tls+16); ::PlotIconID (&r, atNone, ttNone, 'cz'); short whichItem = fTarget->GetValue(); CStr255 itemText; if (whichItem) GetMenuItemText (aquiredMenu, whichItem, itemText); SETMODRECT(r,widgetFrame,top+1,left+tlo,bottom-1,right-tls); DrawTruncTextBox (itemText, r); } void StdPopup::ExecuteSelf (MessageT message, void *param) { fTarget->SetNeedCustomDrawFlag(NeedCustomPopup()); switch (message) { case msg_DrawOrPrint: { // 97-06-07 pkc -- put back SyncMenu otherwise Javascript reflection back // into popup menu list is broken SyncMenu (fTarget->GetMacMenuH()); mExecuteHost = true; break; } case msg_Click: { SMouseDownEvent* event = (SMouseDownEvent*) param; ThrowIfNil_(event); { // Determine which HotSpot was clicked Int16 theHotSpot = fTarget->FindHotSpot(event->whereLocal); if (theHotSpot > 0) { fTarget->FocusDraw(); // Track mouse while it is down if (fTarget->TrackHotSpot(theHotSpot, event->whereLocal, event->macEvent.modifiers)) { // Mouse released inside HotSpot fTarget->HotSpotResult(theHotSpot); } } mExecuteHost = false; } break; } } } void StdPopup::SyncMenu (MenuHandle aquiredMenu) { if (!fDirty) return; int current = CountMItems (aquiredMenu); int want = GetCount(); int add = want - current; if (0 < add) { for (int i = 1; i <= add; i++) AppendMenu (aquiredMenu, "\pTest"); } else if (add < 0) { for (int i = 1; i <= -add; i++) DeleteMenuItem (aquiredMenu, want + 1); } for (int item = 1; item <= want; item++) { CStr255 itemText; itemText = GetText( item ); if ( itemText[ 1 ] == '-' ) itemText = " " + itemText; SetMenuItemText (aquiredMenu, item, itemText ); } if (fTarget->GetMaxValue() != want) fTarget->SetMaxValue (want); (*aquiredMenu)->menuWidth += tls; fDirty = false; } Boolean StdPopup::NeedCustomPopup() const { return false; } ResIDT StdPopup::GetTextTraits() const { return fTarget->GetTextTraits(); } /*----------------------------------------------------------------------------- LCustomizeFontMenu -----------------------------------------------------------------------------*/ class LCustomizeFontMenu : public LCustomizeMenu { public: LCustomizeFontMenu(short fontNum); virtual void Draw (MenuHandle menu, MenuDefUPP* root, Rect *rect, Point hitPt, short *item); virtual void Size (MenuHandle menu, MenuDefUPP* root, Rect *rect, Point hitPt, short *item); virtual void Choose(MenuHandle menu, MenuDefUPP* root, Rect *rect, Point hitPt, short *item); protected: virtual void DrawItemText( Rect& itemrect, Str255 itemtext ); virtual void SetupFont() { ::TextFont(fFontNum); }; private: short fFontNum; }; #pragma mark == LCustomizeFontMenu == LCustomizeFontMenu::LCustomizeFontMenu(short fontNum) : LCustomizeMenu() { fFontNum = fontNum; } void LCustomizeFontMenu::Draw(MenuHandle menu, MenuDefUPP* root, Rect *rect, Point hitPt, short *item) { SetupFont(); LCustomizeMenu::Draw(menu, root, rect, hitPt, item); } void LCustomizeFontMenu::Size(MenuHandle menu, MenuDefUPP* root, Rect *rect, Point hitPt, short *item) { SetupFont(); LCustomizeMenu::Size(menu, root, rect, hitPt, item); } void LCustomizeFontMenu::Choose(MenuHandle menu, MenuDefUPP* root, Rect *rect, Point hitPt, short *item) { SetupFont(); LCustomizeMenu::Choose(menu, root, rect, hitPt, item); } void LCustomizeFontMenu::DrawItemText( Rect& itemrect, Str255 itemtext ) { SetupFont(); LCustomizeMenu::DrawItemText(itemrect,itemtext); } /*----------------------------------------------------------------------------- LMultiFontTextMenu -----------------------------------------------------------------------------*/ class LMultiFontTextMenu : public LCustomizeMenu { public: LMultiFontTextMenu(UMultiFontTextHandler* texthandler, UFontSwitcher* fs); protected: virtual void DrawItemText( Rect& itemrect, Str255 itemtext ) { fTextHandler->DrawString(fFontSwitcher, itemtext); } virtual short MeasureItemText(Str255 itemtext ) { return fTextHandler->StringWidth(fFontSwitcher, itemtext); }; private: UMultiFontTextHandler* fTextHandler; UFontSwitcher* fFontSwitcher; }; LMultiFontTextMenu::LMultiFontTextMenu(UMultiFontTextHandler* texthandler, UFontSwitcher* fs) : LCustomizeMenu() { fTextHandler = texthandler; fFontSwitcher = fs; } #pragma mark - // =========================================================================== // ¥ CGAPopupMenu CGAPopupMenu ¥ // =========================================================================== // --------------------------------------------------------------------------- // ¥ CGAPopupMenu(LStream*) // --------------------------------------------------------------------------- // Construct from data in a Stream CGAPopupMenu::CGAPopupMenu( LStream *inStream) : mNeedCustomDraw(false), super(inStream) { } CGAPopupMenu::~CGAPopupMenu() { } //------------------------------------------------------------------------------------- // CGAPopupMenu::DrawPopupTitle //------------------------------------------------------------------------------------- void CGAPopupMenu::DrawPopupTitle () { if(! mNeedCustomDraw) { // hacky way, depend on mIsUTF8 to decide wheather we use the super class implementation super::DrawPopupTitle(); return; } StColorPenState theColorPenState; StTextState theTextState; // ¥ Get some loal variables setup including the rect for the title ResIDT textTID = GetTextTraitsID (); Rect titleRect; Str255 title; GetCurrentItemTitle ( title ); // ¥ Figure out what the justification is from the text trait and // get the port setup with the text traits UTextTraits::SetPortTextTraits ( textTID ); // ¥ Setup the title justification which is always left justified Int16 titleJust = teFlushLeft; // ¥ Calculate the title rect CalcTitleRect ( titleRect ); // ¥ Setup the text color which by default is black RGBColor textColor; ::GetForeColor ( &textColor ); // ¥ Get the current item's title Str255 currentItemTitle; GetCurrentItemTitle ( currentItemTitle ); // ¥ Loop over any devices we might be spanning and handle the drawing // appropriately for each devices screen depth StDeviceLoop theLoop ( titleRect ); Int16 depth; while ( theLoop.NextDepth ( depth )) { if ( depth < 4 ) // ¥ BLACK & WHITE { // ¥ If the control is dimmed then we use the grayishTextOr // transfer mode to draw the text if ( !IsEnabled ()) { ::RGBForeColor ( &UGAColorRamp::GetBlackColor () ); ::TextMode ( grayishTextOr ); } else if ( IsEnabled () && IsHilited () ) { // ¥ When we are hilited we simply draw the title in white ::RGBForeColor ( &UGAColorRamp::GetWhiteColor () ); } // ¥ Now get the actual title drawn with all the appropriate settings UMultiFontTextHandler *th = UUTF8TextHandler::Instance(); UFontSwitcher *fs = UPropFontSwitcher::Instance(); FontInfo info; th->GetFontInfo(fs, &info); ::MoveTo(titleRect.left, (titleRect.top + titleRect.bottom + info.ascent - info.descent ) / 2); th->DrawString(fs, currentItemTitle); } else // ¥ COLOR { // ¥ If control is selected we always draw the text in the title // hilite color, if requested if ( IsHilited ()) ::RGBForeColor ( &UGAColorRamp::GetWhiteColor() ); // ¥ If the box is dimmed then we have to do our own version of the // grayishTextOr as it does not appear to work correctly across // multiple devices if ( !IsEnabled () || !IsActive ()) { textColor = UGraphicsUtilities::Lighten ( &textColor ); ::TextMode ( srcOr ); ::RGBForeColor ( &textColor ); } // ¥ Now get the actual title drawn with all the appropriate settings UMultiFontTextHandler *th = UUTF8TextHandler::Instance(); UFontSwitcher *fs = UPropFontSwitcher::Instance(); FontInfo info; th->GetFontInfo(fs, &info); ::MoveTo(titleRect.left, (titleRect.top + titleRect.bottom + info.ascent - info.descent) / 2); th->DrawString(fs, currentItemTitle); } } } // CGAPopupMenu::DrawPopupTitle //------------------------------------------------------------------------------------- // // This method is used to calculate the title rect for the currently selected item in // the popup, this title is drawn inside the popup const Int16 gsPopup_RightInset = 24; // Used to position the title rect const Int16 gsPopup_TitleInset = 8; // Apple specification void CGAPopupMenu::CalcTitleRect ( Rect &outRect ) { if(! mNeedCustomDraw) { // hacky way, depend on mIsUTF8 to decide wheather we use the super class implementation super::CalcTitleRect(outRect); return; } StTextState theTextState; StColorPenState thePenState; Int16 bevelWidth = 2; // ¥ Get some loal variables setup including the rect for the title ResIDT textTID = GetTextTraitsID (); // ¥ Get the port setup with the text traits UTextTraits::SetPortTextTraits ( textTID ); // ¥ Figure out the height of the text for the selected font FontInfo fInfo; UFontSwitcher *fs = UPropFontSwitcher::Instance(); UMultiFontTextHandler *th = UUTF8TextHandler::Instance(); th->GetFontInfo(fs, &fInfo); Int16 textHeight = fInfo.ascent + fInfo.descent; Int16 textBaseline = fInfo.ascent; // ¥ Get the local inset frame rectangle CalcLocalPopupFrameRect ( outRect ); ::InsetRect ( &outRect, 0, bevelWidth ); outRect.right -= gsPopup_RightInset; outRect.left += gsPopup_TitleInset; // ¥ Adjust the title rect to match the height of the font outRect.top += (( UGraphicsUtilities::RectHeight ( outRect ) - textBaseline) / 2) - 2; outRect.bottom = outRect.top + textHeight; } // CGAPopupMenu::CalcTitleRect //===================================================================================== // ¥¥ POPUP MENU HANDLING //------------------------------------------------------------------------------------- // CGAPopupMenu::HandlePopupMenuSelect //------------------------------------------------------------------------------------- void CGAPopupMenu::HandlePopupMenuSelect ( Point inPopupLoc, Int16 inCurrentItem, Int16 &outMenuID, Int16 &outMenuItem ) { MenuHandle menuH = GetMacMenuH (); ThrowIfNil_ ( menuH ); if ( menuH ) { // BUG#69583: Make sure we *do* use the system font so that the current // item will be checked properly as in Akbar. So we don't do the LMSetSysFont // stuff that LGAPopup does. // ¥ Handle the actual insertion into the hierarchical menubar ::InsertMenu ( menuH, hierMenu ); FocusDraw (); // ¥ Before we display the menu we need to make sure that we have the // current item marked in the menu. NOTE: we do NOT use the current // item that has been passed in here as that always has a value of one // in the case of a pulldown menu SetupCurrentMenuItem ( menuH, GetValue () ); // ¥ Then we call PopupMenuSelect and wait for it to return Int32 result; // hacky way, depend on mIsUTF8 to decide which implementation to use if (!mNeedCustomDraw) { result = ::PopUpMenuSelect(menuH, inPopupLoc.v, inPopupLoc.h, inCurrentItem ); } else { LMultiFontTextMenu utf8menu(UUTF8TextHandler::Instance(), UPropFontSwitcher::Instance()); result = UCustomizePopUp::PopUpMenuSelect(menuH, &utf8menu, inPopupLoc.v, inPopupLoc.h, inCurrentItem); } // ¥ Then we extract the values from the returned result // these are then passed back out to the caller outMenuID = HiWord ( result ); outMenuItem = LoWord ( result ); // ¥ Finally get the menu removed ::DeleteMenu ( GetPopupMenuResID ()); } } // CGAPopupMenu::HandlePopupMenuSelect