mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
560 lines
16 KiB
C++
560 lines
16 KiB
C++
/*-----------------------------------------------------------------------------
|
|
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 <UDrawingState.h>
|
|
#include <URegistrar.h>
|
|
#include <LStdControl.h>
|
|
// Macintosh headers
|
|
#include <Icons.h>
|
|
#include <Memory.h>
|
|
#include <Menus.h>
|
|
#include <OSUtils.h>
|
|
#include <Traps.h>
|
|
// ANSI headers
|
|
#include <stdio.h>
|
|
#include <UGAColorRamp.h>
|
|
#include <UGraphicsUtilities.h>
|
|
#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
|