home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-06-30 | 10.7 KB | 356 lines | [TEXT/CWIE] |
- // ===========================================================================
- // LAGAPopupMenu.cp
- // ===========================================================================
- //
- // Copyright © 1996 Chrisoft (Christophe ANDRES) All rights reserved.
- //
- // You may use this source code in any application (commercial, shareware, freeware,
- // postcardware, etc), but not remove this notice (no need to acknowledge the use of
- // this class in the about box)
- // You may not sell this source code in any form. This source code may be placed on
- // publicly accessable archive sites and source code disks. It may not be placed on
- // profit archive sites and source code disks without the permission of the author,
- // Christophe ANDRES.
- //
- // This source code is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- //
- // If you make any change or improvement on this class, please send the improved/changed
- // version to : chrisoft@calva.net or Christophe ANDRES
- // 20, rue Prosper Mérimée
- // 67100 STRASBOURG
- // FRANCE
- //
- // ===========================================================================
- // LAGAPopupMenu.h <- double-click + Command-D to see class declaration
- //
- // LAGAPopupMenu is simply a Popup menu class that works in windows with non white backgrounds.
- // The standard Popup Menu CDEF erases in white its title, which in turn looks ugly if your
- // background is NOT white.
- //
- // Note:
- // This class is called LAGAPopupMenu, because it was conceived to be used in conjunction with
- // other “Apple Grayscale Appearance” classes, although it uses only the standard System 7
- // Popup Menu CDEF and henceforth has NOT the look described in the AGA document.
- //
- // Note:
- // The use of this class is only necessary IF the Popup Menu you are using uses a title
- //
- // This class requires AGAColors.cp to be present in your project
- //
- // Version : 1.2
- //
- // Change History (most recent first, date in US form : mm/dd/yy):
- //
- // 06/30/96 ca Public release of version 1.2
- // 06/09/96 bp Brad Pettit <bpettit@aimnet.com>
- // reimplemented using new StAGAEraseHack, since text alignment of the label
- // wasn't always correct for different fonts and label justification.
- // 06/05/96 ca Added RegisterClass method to ease registry
- // Increased version to 1.2
- // 05/17/96 ca Increased version to 1.1
- // Replaced UEnvironment::HasFeature(env_SupportsColor) with PaneInColor
- // Added change history
- // 05/07/96 ca class made available by Christophe ANDRES <chrisoft@calva.net>
- // (version 1.0)
- //
- // To Do:
- //
-
- #include "LAGAPopupMenu.h"
- #include "AGAColors.h"
-
- // begin <06/09/96 bp>
- // Magic: this stack-based class sets up an alternate set of quickdraw procs
- // so that we can undo the lame side-effects of the standard pop-up control, which
- // ignores the port's background color when drawing itself.
- // When it performs an erase on a rectangle that intersects the area that is passed
- // to this objects constructor, we replace the background color with the specified
- // background color.
- // This class should not be created with new(), it should always be instantiated
- // on the stack. Nesting of these objects _may_ not do the right thing.
- // Possible Improvements: If qdProcs were already installed in this port, call them
- // instead of the original function.
- // -Contributed by Brad Pettit <bpettit@aimnet.com>
- class StAGAEraseHack
- {
- public:
-
- StAGAEraseHack(LPane *inPane, const Rect& inAGARect, const RGBColor& inAGAColor);
-
- ~StAGAEraseHack();
-
- private:
-
- static pascal void RectFunction(GrafVerb verb, Rect *rect);
-
- Boolean mWorking;
- GrafPtr mPort;
- CQDProcs mProcs;
- QDProcs *mOldProcs;
- RGBColor mOldColor; // an attempt to support nesting
- Rect mOldRect; // an attempt to support nesting
-
- // we _could_ declare our own custom CQDProcs structure that has these
- // members at the end. But this is easier, and only 14 bytes versus the extra complexity.
- static Rect sOverrideRect;
- static RGBColor sOverrideColor;
- };
-
- Rect StAGAEraseHack::sOverrideRect;
- RGBColor StAGAEraseHack::sOverrideColor;
-
- StAGAEraseHack::StAGAEraseHack (LPane* inPane, const Rect& inAGARect, const RGBColor& inAGAColor)
- {
- mWorking = ::PaneInColor(inPane); // otherwise we don't need to do anything
-
- if (mWorking)
- {
- // save the old rectangle in case this is a nested occurrance of this object
- mOldRect = sOverrideRect;
- sOverrideRect = inAGARect;
-
- // and ditto on the color
- mOldColor = sOverrideColor;
- sOverrideColor = inAGAColor;
-
- // initialize the procs with the standard quickdraw procs
- ::SetStdCProcs(&mProcs);
- // and replace the rect function with ours
- mProcs.rectProc = NewQDRectProc(RectFunction);
-
- ::GetPort(&mPort);
- // save the original grafProcs
- mOldProcs = mPort->grafProcs;
- // and install our grafProcs
- mPort->grafProcs = (QDProcs*) &mProcs;
- }
- }
-
- StAGAEraseHack::~StAGAEraseHack ()
- {
- if(mWorking) // otherwise we didn't do anything
- {
- // restore the original grafProcs
- mPort->grafProcs = (QDProcs*) mOldProcs;
- // and free our routine descriptor
- DisposeRoutineDescriptor(mProcs.rectProc);
-
- // restore the original color and rectangle in case we were nested.
- sOverrideColor = mOldColor;
- sOverrideRect = mOldRect;
- }
- }
-
- // Magic: intercept the rect drawing calls and override the color
- // if we're performing an erase
- // static
- pascal void StAGAEraseHack::RectFunction (GrafVerb verb, Rect *rect)
- {
- if(verb == kQDGrafVerbErase)
- {
- Rect scratch;
- if(::SectRect(rect, &sOverrideRect, &scratch))
- ::RGBBackColor(&sOverrideColor);
- }
-
- ::StdRect(verb, rect); // perform the original quickdraw function
- }
- // end <06/09/96 bp>
-
- // begin <06/05/96 ca>
- void LAGAPopupMenu::RegisterClass ()
-
- {
- URegistrar::RegisterClass(LAGAPopupMenu::class_ID, (ClassCreatorFunc)LAGAPopupMenu::CreateAGAPopupMenuStream);
- }
- // end <06/05/96 ca>
-
- LAGAPopupMenu* LAGAPopupMenu::CreateAGAPopupMenuStream (LStream *inStream)
-
- {
- return(new LAGAPopupMenu(inStream));
- }
-
- LAGAPopupMenu::LAGAPopupMenu (LStream *inStream) : LStdControl(inStream)
-
- {
- Int16 initialMenuItem;
- inStream->ReadData(&initialMenuItem, sizeof(Int16));
-
- InitAGAPopupMenu(initialMenuItem);
- }
-
- LAGAPopupMenu::LAGAPopupMenu (const SPaneInfo &inPaneInfo, MessageT inValueMessage,
- Int16 inTitleOptions, ResIDT inMENUid, Int16 inTitleWidth,
- Int16 inPopupVariation, ResIDT inTextTraitsID, Str255 inTitle,
- OSType inResTypeMENU, Int16 inInitialMenuItem)
- : LStdControl(inPaneInfo, inValueMessage, inTitleOptions, inMENUid, inTitleWidth,
- inPopupVariation, inTextTraitsID, inTitle, inResTypeMENU)
- {
- InitAGAPopupMenu(inInitialMenuItem);
- }
-
-
- void LAGAPopupMenu::DrawSelf()
-
- {
- // For some reason, after a Popup Menu moves, the Control Manager
- // erases the old location of the Popup. All this happens within
- // the Draw1Control() call to draw the Popup at its new location.
- // To prevent this erasure, we restrict the clipping region to
- // just the current location of the Popup.
- #ifdef NOT_DEFINED
- Rect frame;
- CalcLocalFrameRect(frame);
-
- if (::PaneInColor(this))
- {
- frame.left += mTitleWidth;
- {
- StClipRgnState clip;
- clip.ClipToIntersection(frame);
- LStdControl::DrawSelf();
- }
-
- Int16 just = UTextTraits::SetPortTextTraits(mTextTraitsID);
- CalcLocalFrameRect(frame);
- frame.right = frame.left + mTitleWidth;
- ApplyForeAndBackColors();
- ::EraseRect(&frame);
- frame.left += 4;
- frame.right -= 4;
- FontInfo info;
- ::GetFontInfo(&info);
- frame.top += (((frame.bottom - frame.top) - (info.ascent + info.descent)) / 2) - 1;
- Str255 theTitle;
- GetDescriptor(theTitle);
- {
- StClipRgnState clip2;
- clip2.ClipToIntersection(frame);
- UTextDrawing::DrawWithJustification((Ptr)&theTitle[1], theTitle[0], frame, just);
- }
- }
- else
- {
- // If we have no color, then we leave everything to the real popup CDEF
- StClipRgnState clip;
- clip.ClipToIntersection(frame);
- LStdControl::DrawSelf();
- }
- #else
- // begin <06/09/96 bp>
- StClipRgnState clip;
- Rect frame;
- CalcLocalFrameRect(frame);
- clip.ClipToIntersection(frame);
-
- Rect title;
- GetTitleRect(title);
- StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
-
- LStdControl::DrawSelf();
- // end <06/09/96 bp>
- #endif /*NOT_DEFINED*/
- }
-
- MenuHandle LAGAPopupMenu::GetMacMenuH ()
-
- {
- PopupPrivateDataHandle dataH = (PopupPrivateDataHandle)(**GetMacControl()).contrlData;
- return (**dataH).mHandle;
- }
-
- // begin <06/09/96 bp>
- // overridden because it draws the control as a side-effect
- Boolean LAGAPopupMenu::TrackHotSpot (Int16 inHotSpot, Point inPoint)
-
- {
- Boolean result = LStdControl::TrackHotSpot(inHotSpot, inPoint);
-
- // redraw the control, since TrackHotSpot left the background white
- FocusDraw();
- DrawSelf();
-
- return result;
- }
-
- // overridden because it may draw the control as a side-effect
- void LAGAPopupMenu::SetValue (Int32 inValue)
-
- {
- FocusDraw();
-
- Rect title;
- GetTitleRect(title);
- StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
-
- LStdControl::SetValue(inValue);
- }
-
- // overridden because it may draw the control as a side-effect
- void LAGAPopupMenu::SetMaxValue (Int32 inValue)
-
- {
- FocusDraw();
-
- Rect title;
- GetTitleRect(title);
- StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
-
- LStdControl::SetMaxValue(inValue);
- }
-
- // overridden because it may draw the control as a side-effect
- void LAGAPopupMenu::SetMinValue (Int32 inValue)
-
- {
- FocusDraw();
-
- Rect title;
- GetTitleRect(title);
- StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
-
- inherited::SetMinValue(inValue);
- }
-
- void LAGAPopupMenu::GetTitleRect (Rect& outRect)
-
- {
- CalcLocalFrameRect(outRect);
-
- outRect.right = outRect.left + mTitleWidth;
- }
- // end <06/09/96 bp>
-
- void LAGAPopupMenu::InitAGAPopupMenu (Int16 inInitialMenuItem)
-
- {
- mTitleWidth = mMaxValue;
-
- // begin <06/09/96 bp>
- #ifdef NOT_DEFINED
- // we don't use these. This is an example of how to
- // extract the justification and style information for the title
- mTitleJust = mValue & 0x000000ff; // low byte stores justification
- mTitleStyle = ((mValue & 0x0000ff00) & ~popupTitleNoStyle) >> 8; // second byte stores style
- #endif /*NOT_DEFINED*/
- // end <06/09/96 bp>
-
- // Popups use the initial values for other purposes. Control Manager
- // determines min/max from the size of the Menu. So now we have to
- // adjust the value, min, and max stored by LControl.
-
- mValue = ::GetControlValue(mMacControlH);
- mMinValue = ::GetControlMinimum(mMacControlH);
- mMaxValue = ::GetControlMaximum(mMacControlH);
-
- if (inInitialMenuItem != mValue)
- {
- ::SetControlValue(mMacControlH, inInitialMenuItem);
- mValue = ::GetControlValue(mMacControlH);
- }
- }
-
-