home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1997 February
/
macformat-047.iso
/
Shareware Plus
/
Developers
/
The Gray Council 1.2.1
/
source
/
Core
/
GrayCouncil.cpp
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1996-11-07
|
311.1 KB
|
11,275 lines
|
[
TEXT/CWIE
]
//
// The Gray Council
// Copyright ©1996 by Trygve Isaacson. All Rights Reserved.
//
// Before using any of the Gray Council source code, read and
// follow the licensing info in the accompanying documentation
// or contact:
// <trygve@bombaydigital.com>
// <http://www.bombaydigital.com>
//
// Also check the web site above to make sure you have the latest version!
//
// The Gray Council provides a set of standard C++ classes that implement
// the standard Apple Grayscale Appearance. The core classes do not
// require any other code such as a particular class framework.
// There are separate files provided that plug The Gray Council core
// into class frameworks.
//
// Classes defined below:
// AGAObject -- abstract base class for most others
// MExclusiveObject -- mixin class for mutual exclusivity (e.g. radio)
// AGATextStyle -- text style attributes container
// AGADrawingEnvironment -- stack-based save/restore class for drawing attributes
// AGAStaticText -- simple string object
// AGAPushButton -- push button with auto default outline capability
// AGACheckBox -- check box with mixed state capability
// AGAOffscreenImage -- class for storing and drawing an offscreen pixmap
// AGARadioButton -- radio button with mixed state capability
// MIconButtonObject -- mixin class for icon buttons
// AGAIconPushButton -- AGAPushButton subclass for icon push buttons
// AGAIconCheckBox -- AGACheckBox subclass for on/off icon buttons
// AGAIconRadioButton -- AGARadioButton subclass for mutually exclusive
// on/off icon buttons
// AGATrackingIndicator -- abstract superclass for scroll bar and slider
// AGAScrollBar -- scroll bar with 32-bit values, live tracking, and
// proportional indicator capabilities
// AGASlider -- slider with pointy or rectangular indicator, optional
// labels, live tracking, proportional indicator capabilities
// AGAPopupMenu -- popup menu with optional title
// AGACustomPopupMenuSizer -- stack-based class to make PopupMenuSelect use custom font/size
// AGALittleArrows -- little up/down arrows with notification
// AGADisclosureTriangle -- disclosure triangle with animation
// AGAProgressIndicator -- determinate or indeterminate progress gauge
// with moving determinate origin capability
// AGASeparator -- separator line with automatic directionality
// AGAGroupBox -- primary or secondary group box with optional title or
// room for external title or control
// AGATabPanel -- folder tabs for switching panels
// GDIterator -- stack-based class for multi-screen drawing
//
#include "GrayCouncil.h"
#include <limits.h>
#include <LowMem.h>
#pragma segment GrayCouncilCore1
//
// Initialization -----------------------------------------------------
//
// Must be called by client application after initializing the toolbox,
// and before any other Gray Council calls are made.
// The framework-specific initialization functions call this automatically.
//
OSErr InitGrayCouncil()
{
OSErr result;
SInt32 gestaltResponse;
//
// Initialize some basic globals.
//
// Default flags. Only live scrolling is on by default.
gAGADefaults = kAGALiveScrolling;
// Set global Color QuickDraw flag.
result = ::Gestalt(gestaltQuickdrawVersion, &gestaltResponse);
gAGAHasColorQD = (result == noErr) && (gestaltResponse != gestaltOriginalQD);
// Allocate the group container.
gGroupsContainer = new AGAGroupsContainer;
// Try to allocate the offscreen images.
result = AGARadioButton::AllocateRadioImages();
if (result == noErr)
result = AGAProgressIndicator::AllocateProgressImages();
if (result == noErr)
result = AGATabPanel::AllocateTabImages();
return result;
}
//
// Static routines used only inside this file -------------------------
//
static SInt16 MinSInt16(SInt16 a, SInt16 b) { return (a < b) ? a : b; }
static SInt16 MaxSInt16(SInt16 a, SInt16 b) { return (a > b) ? a : b; }
static SInt32 MinSInt32(SInt32 a, SInt32 b) { return (a < b) ? a : b; }
static SInt32 MaxSInt32(SInt32 a, SInt32 b) { return (a > b) ? a : b; }
static void DelayFuture(SInt32 delayTicks)
{
// Delay for the specified number of ticks.
SInt32 dontCare;
::Delay(delayTicks, &dontCare);
}
static void DelayFutureWhileStillDown(SInt32 delayTicks)
{
// Delay for the specified number of ticks, but bail
// out if the user lets go of the mouse first.
SInt32 future = delayTicks + ::TickCount();
while (::StillDown() && (::TickCount() < future))
{};
}
static SInt32 RuntimeJustify(SInt32 userJust)
{
// Return the actual runtime justification value for
// the supplied value. The caller can use the result
// alone to know determine drawing direction.
// If the supplied value specifies default, we need
// to check the current system script direction.
// Otherwise, whatever was specified is OK as is.
if (userJust == teFlushDefault)
{
if (::GetSysDirection() == 0)
return teFlushLeft;
else
return teFlushRight;
}
else
return userJust;
}
//
// AGATextStyle --------------------------------------------------------
//
AGATextStyle::AGATextStyle()
{
// Default constructor, use system font.
mFontNum = systemFont; // typically Chicago
mFontSize = 0; // application size, typically 12-point
mFontStyle = normal;
}
AGATextStyle::AGATextStyle(SInt16 fontNum, SInt16 fontSize, Style fontStyle)
{
// Construct with direct parameters.
mFontNum = fontNum;
mFontSize = fontSize;
mFontStyle = fontStyle;
}
AGATextStyle::AGATextStyle(StringPtr fontName, SInt16 fontSize, Style fontStyle)
{
// Construct by converting font name to font number.
::GetFNum(fontName, &mFontNum);
mFontSize = fontSize;
mFontStyle = fontStyle;
}
AGATextStyle::AGATextStyle(const TextStyle& textStyle)
{
// Construct by copying another text style.
mFontNum = textStyle.tsFont;
mFontSize = textStyle.tsSize;
mFontStyle = textStyle.tsFace;
}
void AGATextStyle::PrepareForDrawing() const
{
// Set the text pen for subsequent drawing.
::TextFont(mFontNum);
::TextSize(mFontSize);
::TextFace(mFontStyle);
}
//
// AGADrawingEnvironment ---------------------------------------------------------------
//
AGADrawingEnvironment::AGADrawingEnvironment()
{
// Save current environment, then cleanse the pen.
this->SaveEnvironment();
this->Cleanse();
}
AGADrawingEnvironment::~AGADrawingEnvironment()
{
this->RestoreEnvironment();
}
void AGADrawingEnvironment::SaveEnvironment()
{
// Save all text/pen attributes that we will change.
GrafPtr currentPort;
::GetPort(¤tPort);
::GetPenState(&mSavedPenState);
::GetForeColor(&mSavedForeColor);
::GetBackColor(&mSavedBackColor);
mSavedFontNum = currentPort->txFont;
mSavedFontSize = currentPort->txSize;
mSavedFontStyle = currentPort->txFace;
}
void AGADrawingEnvironment::RestoreEnvironment()
{
// Restore text/pen attributes that we saved.
::SetPenState(&mSavedPenState);
::RGBForeColor(&mSavedForeColor);
::RGBBackColor(&mSavedBackColor);
::TextFont(mSavedFontNum);
::TextSize(mSavedFontSize);
::TextFace(mSavedFontStyle);
}
void AGADrawingEnvironment::Cleanse()
{
// Put the pen into a nice clean state.
::PenNormal(); // pen size 1,1, solid black pattern, srcOr
::RGBForeColor(&gAGARamp[rB]); // black fore color
::RGBBackColor(&gAGARamp[rW]); // white back color
gAGAStdSystemStyle.PrepareForDrawing(); // system font 12 point
}
//
// AGAObject ---------------------------------------------------------------
//
AGAObject::AGAObject(Rect* bounds)
{
// Construct enabled.
mBounds = *bounds;
mEnabled = true;
mEnabledBackgroundColor = gAGARamp[r2];
mDisabledBackgroundColor = gAGARamp[r2];
}
AGAObject::~AGAObject()
{
}
void AGAObject::GetObjectBounds(Rect* bounds)
{
// Return current bounds.
*bounds = mBounds;
}
void AGAObject::SetObjectBounds(Rect* bounds, Boolean redraw)
{
// Change bounds, redraw if specified.
mBounds = *bounds;
if (redraw)
this->DrawObject();
}
void AGAObject::DrawObject()
{
// Override to draw particular type of object.
}
Boolean AGAObject::ContainsMouse(Point mouseLocation)
{
// Return true if mouse will hit object.
return ::PtInRect(mouseLocation, &mBounds);
}
Boolean AGAObject::TrackMouse(Point /*mouseLocation*/)
{
if (! mEnabled)
return false;
// Process mouse tracking, return true if tracking
// eventually "did something". Return false if
// tracking had no ultimate effect, e.g. mouse
// up outside a push button.
Boolean finishedIn = false;
Boolean wasIn = false;
Boolean isIn;
Boolean isButtonDown = true; // ensure at least one time through
Point newMouseLocation;
while (isButtonDown)
{
::GetMouse(&newMouseLocation); // gives local coordinates
isIn = this->HitTest(newMouseLocation);
if (isIn != wasIn)
this->SetTrackingState(isIn);
wasIn = isIn;
isButtonDown = ::StillDown();
}
if (isIn) // if finished IN, restore normal appearance
this->SetTrackingState(kTrackingOut);
return isIn;
}
void AGAObject::SetEnable(Boolean isEnabled, Boolean redraw)
{
// Set object enable state, redraw if specified.
mEnabled = isEnabled;
if (redraw)
this->DrawObject();
}
void AGAObject::SetBackgroundColors(RGBColor* enabledColor, RGBColor* disabledColor)
{
// Set colors to be used when erasing background.
// Most views don't need this. Default is AGA ramp r2.
// AGAStaticText and AGADisclosureTriangle need to
// erase their background, so if your background is
// not r2 (white, for example), call this to set it.
// Also, objects contained in tab panel views need
// r1 when enabled, and r2 when disabled, so that's
// an even wackier case; the adapter classes handle
// it for you.
mEnabledBackgroundColor = *enabledColor;
mDisabledBackgroundColor = *disabledColor;
}
SInt32 AGAObject::GetValue()
{
return 0; // overriden for objects that have a useful value
}
void AGAObject::SetValue(SInt32 /*newValue*/, Boolean /*redraw*/)
{
// overriden for objects that have a useful value
}
Boolean AGAObject::HitTest(Point mouseLocation)
{
// Return true if mouse is inside tracking area of
// object. This function may be overridden for
// classes that do not have simple rectangular
// boundary hit testing.
return ::PtInRect(mouseLocation, &mBounds);
}
void AGAObject::SetTrackingState(Boolean /*isIn*/)
{
// Override to draw the object in the appropriate
// state during tracking. If isIn is true, it means
// that the mouse is now in the positive hit test
// area of the object.
}
void AGAObject::ApplyBackgroundColor()
{
// Use the proper background color and apply it as
// the current foreground color suitable for a
// subsequent PaintRect or similar call.
if (mEnabled)
::RGBForeColor(&mEnabledBackgroundColor);
else
::RGBForeColor(&mDisabledBackgroundColor);
}
//
// AGAStaticText ---------------------------------------------------------------
//
// This class draws a static text label.
//
AGAStaticText::AGAStaticText(Rect* bounds, const AGATextStyle& textStyle, SInt32 justification)
: AGAObject(bounds)
{
// Construct with empty string.
mJustification = justification;
mTitle[0];
mTextStyle = textStyle;
}
AGAStaticText::AGAStaticText(Rect* bounds, const AGATextStyle& textStyle, SInt32 justification, StringPtr title)
: AGAObject(bounds)
{
// Construct with supplied string.
mJustification = justification;
AGA_PLstrcpy(mTitle, title);
mTextStyle = textStyle;
}
AGAStaticText::AGAStaticText(Rect* bounds, const AGATextStyle& textStyle, SInt32 justification, SInt16 stringListResourceID, SInt16 stringIndex)
: AGAObject(bounds)
{
// Construct by getting string from specified resource.
mJustification = justification;
::GetIndString(mTitle, stringListResourceID, stringIndex);
mTextStyle = textStyle;
}
AGAStaticText::~AGAStaticText()
{
}
void AGAStaticText::DrawObject()
{
AGADrawingEnvironment env;
// Paint over possible obsolete text, draw current text.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
this->ApplyBackgroundColor();
else
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&mBounds);
RGBColor teBackgroundColor;
::GetForeColor(&teBackgroundColor); // fg color right now is what the TE must leave in the bg
AGATextBox(&mTitle[1], mTitle[0], &mBounds, mJustification, mEnabled ? kNormalOutput : kDisabledOutput, deep, mTextStyle, &teBackgroundColor);
}
}
void AGAStaticText::SetTitle(StringPtr title, Boolean redraw)
{
// Change text, redraw if specified.
AGA_PLstrcpy(mTitle, title);
if (redraw)
this->DrawObject();
}
//
// AGAPushButton ---------------------------------------------------------------
//
// This class implements a standard text pushbutton object.
//
AGAPushButton::AGAPushButton(Rect* bounds, const AGATextStyle& textStyle)
: AGAObject(bounds)
{
// Construct with initial empty button title.
mIsDefault = false;
mFrameInside = true;
mTitle[0];
mTextStyle = textStyle;
}
AGAPushButton::AGAPushButton(Rect* bounds, const AGATextStyle& textStyle, StringPtr title)
: AGAObject(bounds)
{
// Construct with specified button title.
mIsDefault = false;
mFrameInside = true;
AGA_PLstrcpy(mTitle, title);
mTextStyle = textStyle;
}
AGAPushButton::AGAPushButton(Rect* bounds, const AGATextStyle& textStyle, SInt16 stringListResourceID, SInt16 stringIndex)
: AGAObject(bounds)
{
// Construct by getting button title from specified resource.
mIsDefault = false;
mFrameInside = true;
::GetIndString(mTitle, stringListResourceID, stringIndex);
mTextStyle = textStyle;
}
AGAPushButton::~AGAPushButton()
{
}
void AGAPushButton::DrawObject()
{
// Draw button in normal unpressed state.
this->DrawButton(kNotPressed);
}
void AGAPushButton::SetTitle(StringPtr title, Boolean redraw)
{
// Change button title, redraw if specified.
AGA_PLstrcpy(mTitle, title);
if (redraw)
this->DrawObject();
}
void AGAPushButton::SetDefault(Boolean isDefault, Boolean frameInside)
{
// Set default state. If mIsDefault is true, the button will
// be drawn with a default button outline. If mFrameInside
// is true, the outline will be inside mBounds and the button
// will be drawn inset from there; if mFrameInside is false,
// the outline will be outside mBounds and the button will
// be drawn at mBounds.
mIsDefault = isDefault;
mFrameInside = frameInside;
}
Boolean AGAPushButton::IsDefault()
{
// Return true if this button has a default outline.
return mIsDefault;
}
void AGAPushButton::DrawButton(Boolean pressed)
{
AGADrawingEnvironment env;
// Draw the button in the appropriate state.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (! mEnabled)
this->DrawButtonDisabled(deep);
else if (pressed)
this->DrawButtonPressed(deep);
else
this->DrawButtonNormal(deep);
}
}
Boolean AGAPushButton::HitTest(Point mouseLocation)
{
// Return true if the mouse is in the button.
// Account for case where default button outline
// is inside mBounds.
Rect r = mBounds;
if (mIsDefault && mFrameInside)
::InsetRect(&r, 3, 3);
return ::PtInRect(mouseLocation, &r);
}
void AGAPushButton::SetTrackingState(Boolean isIn)
{
// Draw the button pressed or unpressed as specified.
this->DrawButton(isIn);
}
void AGAPushButton::DrawButtonNormal(Boolean deep)
{
// Draw the button in enabled/unpressed state.
Rect r = mBounds;
if (mIsDefault && mFrameInside)
::InsetRect(&r, 3, 3);
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r2]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(r.right - r.left - 6, 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, r.bottom - r.top - 6);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(- (r.right - r.left - 6), 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, -(r.bottom - r.top - 6));
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
// Add 1st inner pixels.
::MoveTo(r.left + 1, r.top + 2);
::RGBForeColor(&gAGARamp[r4]);
::Line(0, 0);
::Move(1, -1);
::Line(0, 0);
::Move(r.right - r.left - 5, 0);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(0, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, r.bottom - r.top - 6);
::Line(-1, 0);
::Line(0, 1);
::Line(- (r.right - r.left - 6), 0);
::RGBForeColor(&gAGARamp[r4]);
::Move(-1, 0);
::Line(-1, -1);
// Add 2nd inner pixels.
::MoveTo(r.left + 2, r.bottom - 4);
::RGBForeColor(&gAGARamp[rW]);
::Line(0, -(r.bottom - r.top - 6));
::Line(1, 1);
::Line(0, -1);
::Line(r.right - r.left - 7, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(0, r.bottom - r.top - 7);
::Line(-1, 0);
::Line(0, 1);
::Line(- (r.right - r.left - 7), 0);
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rW]);
::PaintRoundRect(&r, 7, 7);
::RGBForeColor(&gAGARamp[rB]);
::FrameRoundRect(&r, 7, 7);
}
// Draw the title.
AGAStringOut(mTitle, &r, truncMiddle, teJustCenter, kNormalOutput, deep, mTextStyle);
// Draw the default button outline.
this->DrawOutlineNormal(deep);
}
void AGAPushButton::DrawButtonPressed(Boolean deep)
{
// Draw the button in enabled/pressed state.
Rect r = mBounds;
if (mIsDefault && mFrameInside)
::InsetRect(&r, 3, 3);
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r9]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(r.right - r.left - 6, 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, r.bottom - r.top - 6);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(- (r.right - r.left - 6), 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, -(r.bottom - r.top - 6));
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
// Add 1st inner pixels.
::MoveTo(r.left + 1, r.bottom - 3);
::RGBForeColor(&gAGARamp[r11]);
::Line(0, -(r.bottom - r.top - 5));
::Line(1, 0);
::Line(0, -1);
::Line(r.right - r.left - 5, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[r7]);
::Line(0, r.bottom - r.top - 6);
::Line(-1, 0);
::Line(0, 1);
::Line(- (r.right - r.left - 5), 0);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, 0);
// Add 2nd inner pixels.
::MoveTo(r.left + 2, r.bottom - 4);
::RGBForeColor(&gAGARamp[r10]);
::Line(0, -(r.bottom - r.top - 7));
::Line(1, 0);
::Line(0, -1);
::Line(r.right - r.left - 7, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, r.bottom - r.top - 7);
::Line(-1, 0);
::Line(0, 1);
::Line(- (r.right - r.left - 7), 0);
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rB]);
::PaintRoundRect(&r, 7, 7);
}
// Draw the title.
AGAStringOut(mTitle, &r, truncMiddle, teJustCenter, kInverseOutput, deep, mTextStyle);
// Draw the default button outline.
this->DrawOutlineNormal(deep);
}
void AGAPushButton::DrawButtonDisabled(Boolean deep)
{
// Draw the button in disabled/unpressed state.
Rect r = mBounds;
if (mIsDefault && mFrameInside)
::InsetRect(&r, 3, 3);
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r2]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[r7]);
::Line(0, 0);
::Move(1, -1);
::Line(0, 0);
::Move(1, 0);
::Line(r.right - r.left - 6, 0);
::Line(0, 0);
::Move(1, 1);
::Line(0, 0);
::Move(1, 1);
::Line(0, 0);
::Move(0, 1);
::Line(0, r.bottom - r.top - 6);
::Line(0, 0);
::Move(-1, 1);
::Line(0, 0);
::Move(-1, 1);
::Line(0, 0);
::Move(-1, 0);
::Line(- (r.right - r.left - 6), 0);
::Line(0, 0);
::Move(-1, -1);
::Line(0, 0);
::Move(-1, -1);
::Line(0, 0);
::Move(0, -1);
::Line(0, -(r.bottom - r.top - 6));
::Line(0, 0);
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rW]);
::PaintRoundRect(&r, 7, 7);
::RGBForeColor(&gAGARamp[rB]);
::FrameRoundRect(&r, 7, 7);
}
// Draw the title.
AGAStringOut(mTitle, &r, truncMiddle, teJustCenter, kDisabledOutput, deep, mTextStyle);
// Draw the default button outline.
this->DrawOutlineDisabled(deep);
if (! deep)
{
if (mIsDefault)
::InsetRect(&r, -3, -3);
::RGBForeColor(&gAGARamp[rB]);
::PenPat(&qd.gray);
::PenMode(patBic);
::PaintRect(&r);
::PenNormal();
}
}
void AGAPushButton::DrawOutlineNormal(Boolean deep)
{
// Draw the default button outline in normal
// state if the button has one. It may be either
// inside or outside mBounds.
// If we are drawing the outline outside the normal
// bounds, we should force the clipping to include
// that outside area, because the framework or whoever
// may have reduced clipping to our bounds.
if (! mIsDefault)
return;
Rect r = mBounds;
if (! mFrameInside)
::InsetRect(&r, -3, -3);
if (deep)
{
// Draw the frame.
::MoveTo(r.left + 1, r.top + 2);
::RGBForeColor(&gAGARamp[rB]);
::Line(1, -1);
::Move(1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(r.right - r.left - 8, 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(1, 1);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, r.bottom - r.top - 8);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(-1, 1);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(- (r.right - r.left - 8), 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(-1, -1);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, -(r.bottom - r.top - 8));
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
// Draw the interior.
::MoveTo(r.left + 1, r.bottom - 4);
::RGBForeColor(&gAGARamp[r2]);
::Line(0, -(r.bottom - r.top - 7));
::Line(1, 0);
::Line(0, -1);
::Line(1, 0);
::Line(0, -1);
::Line(r.right - r.left - 8, 0);
::Move(1, 0);
::RGBForeColor(&gAGARamp[r3]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r4]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r7]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, r.bottom - r.top - 8);
::Line(-2, 2);
::Line(-(r.right - r.left - 8), 0);
::Move(-1, 0);
::RGBForeColor(&gAGARamp[r7]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r4]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r3]);
::Line(0, 0);
::Move(1, 0);
::RGBForeColor(&gAGARamp[r5]);
::Line(0, -(r.bottom - r.top - 8));
::Line(2, -2);
::Line(r.right - r.left - 8, 0);
::Line(0, 1);
::Line(1, 0);
::Line(0, r.bottom - r.top - 8);
::Line(-2, 2);
::Line(-(r.right - r.left - 8), 0);
::Line(0, -1);
::Move(0, -1);
::RGBForeColor(&gAGARamp[r8]);
::Line(1, 1);
::MoveTo(r.left + 3, r.top + 4);
::Line(1, -1);
::MoveTo(r.right -5, r.top + 3);
::Line(1, 1);
::MoveTo(r.right -5, r.bottom - 4);
::Line(1, -1);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r7]);
::Line(-1, 1);
}
else
{
::RGBForeColor(&gAGARamp[rB]);
::PenSize(2, 2);
::FrameRoundRect(&r, 11, 11);
::PenSize(1, 1);
}
}
void AGAPushButton::DrawOutlineDisabled(Boolean deep)
{
// Draw the default button outline in disabled
// state if the button has one. It may be either
// inside or outside mBounds.
if (! mIsDefault)
return;
Rect r = mBounds;
if (! mFrameInside)
::InsetRect(&r, -3, -3);
if (deep)
{
// Draw the frame.
::MoveTo(r.left + 1, r.top + 2);
::RGBForeColor(&gAGARamp[r7]);
::Line(1, -1);
::Move(1, -1);
::Line(0, 0);
::Move(1, 0);
::Line(r.right - r.left - 8, 0);
::Line(0, 0);
::Move(1, 1);
::Line(1, 1);
::Move(1, 1);
::Line(0, 0);
::Move(0, 1);
::Line(0, r.bottom - r.top - 8);
::Line(0, 0);
::Move(-1, 1);
::Line(-1, 1);
::Move(-1, 1);
::Line(0, 0);
::Move(-1, 0);
::Line(- (r.right - r.left - 8), 0);
::Line(0, 0);
::Move(-1, -1);
::Line(-1, -1);
::Move(-1, -1);
::Line(0, 0);
::Move(0, -1);
::Line(0, -(r.bottom - r.top - 8));
::Line(0, 0);
// Draw the interior.
::MoveTo(r.left + 1, r.bottom - 4);
::RGBForeColor(&gAGARamp[r4]);
::Line(0, -(r.bottom - r.top - 7));
::Line(1, 0);
::Line(0, -1);
::Line(1, 0);
::Line(0, -1);
::Line(r.right - r.left - 8, 0);
::Move(3, 2);
::Line(0, r.bottom - r.top - 7);
::Line(-1, 0);
::Line(0, 1);
::Line(-1, 0);
::Line(0, 1);
::Line(-(r.right - r.left - 7), 0);
::Move(-2, -2);
::Line(1, 1);
::Line(0, -(r.bottom - r.top - 7));
::Line(1, 0);
::Line(0, -1);
::Line(1, 0);
::Line(0, -1);
::Line(r.right - r.left - 7, 0);
::Line(-1, -1);
::Move(-1, 2);
::Line(2, 0);
::Move(-1, 1);
::Line(1, 0);
::Line(0, r.bottom - r.top - 9);
::Line(-1, 0);
::Line(0, 1);
::Line(-1, 0);
::Line(0, 1);
::Line(-(r.right - r.left - 8), 0);
::Line(0, -2);
::Line(1, 1);
}
else
{
::RGBForeColor(&gAGARamp[rB]);
::PenSize(2, 2);
::FrameRoundRect(&r, 11, 11);
::PenSize(1, 1);
}
}
//
// AGACheckBox ---------------------------------------------------------------
//
// This class implements a standard checkbox object with the additional
// capability of supporting mixed state.
//
AGACheckBox::AGACheckBox(Rect* bounds, const AGATextStyle& textStyle, Boolean automaticState)
: AGAObject(bounds)
{
// Construct with initial empty button title.
mValue = kCheckBoxOff;
mAutomaticState = automaticState;
mTitle[0];
mTextStyle = textStyle;
}
AGACheckBox::AGACheckBox(Rect* bounds, const AGATextStyle& textStyle, StringPtr title, Boolean automaticState)
: AGAObject(bounds)
{
// Construct with specified button title.
mValue = kCheckBoxOff;
mAutomaticState = automaticState;
AGA_PLstrcpy(mTitle, title);
mTextStyle = textStyle;
}
AGACheckBox::AGACheckBox(Rect* bounds, const AGATextStyle& textStyle, SInt16 stringListResourceID, SInt16 stringIndex, Boolean automaticState)
: AGAObject(bounds)
{
// Construct by getting button title from specified resource.
mValue = kCheckBoxOff;
mAutomaticState = automaticState;
::GetIndString(mTitle, stringListResourceID, stringIndex);
mTextStyle = textStyle;
}
AGACheckBox::~AGACheckBox()
{
}
void AGACheckBox::DrawObject()
{
// Draw button in normal unpressed state.
this->DrawButton(kNotPressed);
}
Boolean AGACheckBox::TrackMouse(Point mouseLocation)
{
// If inherited tracking succeeded and we are set to
// automatically change our state, toggle it.
Boolean wasItHit = AGAObject::TrackMouse(mouseLocation);
if (wasItHit && mAutomaticState)
this->SetValue((mValue == kCheckBoxOn) ? kCheckBoxOff : kCheckBoxOn, kRedraw);
return wasItHit;
}
void AGACheckBox::SetTitle(StringPtr title, Boolean redraw)
{
// Change button title, redraw if specified.
AGA_PLstrcpy(mTitle, title);
if (redraw)
this->DrawObject();
}
SInt32 AGACheckBox::GetValue()
{
// Return current state.
return mValue;
}
void AGACheckBox::SetValue(SInt32 newValue, Boolean redraw)
{
// Set current state, redraw if specified and necessary.
if (newValue != mValue)
{
mValue = newValue;
if (redraw)
{
this->DrawButton(kNotPressed);
}
}
}
void AGACheckBox::DrawButton(Boolean pressed)
{
AGADrawingEnvironment env;
// Draw the button in the appropriate state.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (! mEnabled)
this->DrawButtonDisabled(deep);
else if (pressed)
this->DrawButtonPressed(deep);
else
this->DrawButtonNormal(deep);
}
}
void AGACheckBox::SetTrackingState(Boolean isIn)
{
// Draw the button pressed or unpressed as specified.
this->DrawButton(isIn);
}
void AGACheckBox::DrawButtonNormal(Boolean deep)
{
// Draw the button in enabled/unpressed state.
Rect r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.bottom = r.top + kCheckBoxSize;
r.right = r.left + kCheckBoxSize;
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r2]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
// Draw the edges.
::MoveTo(r.left + 1, r.bottom - 3);
::RGBForeColor(&gAGARamp[rW]);
::Line(0, -8);
::Line(8, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r7]);
::Line(0, 8);
::Line(-8, 0);
if (mValue == kCheckBoxOn)
{
// Draw the X and its shadow.
::MoveTo(r.left + 3, r.top + 2);
::RGBForeColor(&gAGARamp[rB]);
::Line(5, 5);
::Move(0, 1);
::Line(-5, -5);
::Move(0, 4);
::Line(5, -5);
::Move(0, 1);
::Line(-5, 5);
::Move(1, 0);
::RGBForeColor(&gAGARamp[r8]);
::Line(1, -1);
::Move(2, -2);
::Line(2, -2);
::Move(0, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(-1, 1);
::Move(-2, 2);
::Line(-2, 2);
::Move(5, 0);
::Line(0, 0);
::Move(0, -1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, 0);
}
else if (mValue == kCheckBoxMixed)
{
// Draw the dash and its shadow.
::MoveTo(r.left + 3, r.top + 5);
::PenSize(2, 2);
::RGBForeColor(&gAGARamp[rB]);
::Line(4, 0);
::MoveTo(r.left + 4, r.top + 7);
::PenSize(1, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(5, 0);
::Line(-2, 0);
}
}
else
{
// Paint white over previous junk, if any.
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
// Paint frame.
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
// Draw check or dash.
if (mValue == kCheckBoxOn)
{
::PenSize(1, 1);
::MoveTo(r.left, r.top);
::Line(kCheckBoxSize-1, kCheckBoxSize-1);
::Move(-(kCheckBoxSize-1), 0);
::Line(kCheckBoxSize-1, -(kCheckBoxSize-1));
}
else if (mValue == kCheckBoxMixed)
{
::PenSize(1, 2);
::MoveTo(r.left + 3, r.top + 5);
::Line(5, 0);
}
::PenNormal();
}
// Draw the title.
r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.left += (kCheckBoxSize + 4);
r.bottom = r.top + kCheckBoxSize;
AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
}
void AGACheckBox::DrawButtonPressed(Boolean deep)
{
// Draw the button in enabled/pressed state.
Rect r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.bottom = r.top + kCheckBoxSize;
r.right = r.left + kCheckBoxSize;
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r8]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
// Draw the edges.
::MoveTo(r.left + 1, r.bottom - 3);
::RGBForeColor(&gAGARamp[r10]);
::Line(0, -8);
::Line(8, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r6]);
::Line(0, 8);
::Line(-8, 0);
if (mValue == kCheckBoxOn)
{
// Draw the X and its shadow.
::MoveTo(r.left + 3, r.top + 2);
::RGBForeColor(&gAGARamp[rB]);
::Line(5, 5);
::Move(0, 1);
::Line(-5, -5);
::Move(0, 4);
::Line(5, -5);
::Move(0, 1);
::Line(-5, 5);
::Move(1, 0);
::RGBForeColor(&gAGARamp[r11]);
::Line(1, -1);
::Move(2, -2);
::Line(2, -2);
::Move(0, 1);
::RGBForeColor(&gAGARamp[r10]);
::Line(-1, 1);
::Move(-2, 2);
::Line(-2, 2);
::Move(5, 0);
::Line(0, 0);
::Move(0, -1);
::RGBForeColor(&gAGARamp[r11]);
::Line(0, 0);
}
else if (mValue == kCheckBoxMixed)
{
// Draw the dash and its shadow.
::MoveTo(r.left + 3, r.top + 5);
::PenSize(2, 2);
::RGBForeColor(&gAGARamp[rB]);
::Line(4, 0);
::MoveTo(r.left + 4, r.top + 7);
::PenSize(1, 1);
::RGBForeColor(&gAGARamp[r10]);
::Line(5, 0);
::Line(-2, 0);
}
}
else
{
// Paint white over previous junk, if any.
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
// Paint frame.
::RGBForeColor(&gAGARamp[rB]);
::PenSize(2, 2);
::FrameRect(&r);
// Draw check or dash.
if (mValue == kCheckBoxOn)
{
::PenSize(1, 1);
::MoveTo(r.left, r.top);
::Line(kCheckBoxSize-1, kCheckBoxSize-1);
::Move(-(kCheckBoxSize-1), 0);
::Line(kCheckBoxSize-1, -(kCheckBoxSize-1));
}
else if (mValue == kCheckBoxMixed)
{
::PenSize(1, 2);
::MoveTo(r.left + 3, r.top + 5);
::Line(5, 0);
}
::PenNormal();
}
// Draw the title.
r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.left += (kCheckBoxSize + 4);
r.bottom = r.top + kCheckBoxSize;
AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
}
void AGACheckBox::DrawButtonDisabled(Boolean deep)
{
// Draw the button in disabled/unpressed state.
Rect r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.bottom = r.top + kCheckBoxSize;
r.right = r.left + kCheckBoxSize;
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r2]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::RGBForeColor(&gAGARamp[r7]);
::FrameRect(&r);
if (mValue == kCheckBoxOn)
{
// Draw the X.
::PenSize(1, 2);
::MoveTo(r.left + 3, r.top + 2);
::RGBForeColor(&gAGARamp[r7]);
::Line(5, 5);
::Move(-5, 0);
::Line(5, -5);
::Move(0, 1);
}
else if (mValue == kCheckBoxMixed)
{
// Draw the dash.
::MoveTo(r.left + 3, r.top + 5);
::PenSize(2, 2);
::RGBForeColor(&gAGARamp[r7]);
::Line(4, 0);
}
}
else
{
// Paint white over previous junk, if any.
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
// Paint frame.
::PenPat(&qd.gray);
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
// Draw check or dash.
if (mValue == kCheckBoxOn)
{
::PenPat(&qd.black); // 1-pixel diagonals can disappear when qd.gray
::MoveTo(r.left + 2, r.top + 2);
::Line(kCheckBoxSize-5, kCheckBoxSize-5);
::Move(-(kCheckBoxSize-5), 0);
::Line(kCheckBoxSize-5, -(kCheckBoxSize-5));
}
else if (mValue == kCheckBoxMixed)
{
::PenSize(1, 2);
::MoveTo(r.left + 3, r.top + 5);
::Line(5, 0);
}
::PenNormal();
}
// Draw the title.
r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.left += (kCheckBoxSize + 4);
r.bottom = r.top + kCheckBoxSize;
AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kDisabledOutput, deep, mTextStyle);
}
//
// AGAGroupsContainer --------------------------------------------------------
//
// This class is used internally to maintain the MExclusiveObject
// behavior that allows radio buttons to automatically maintain
// standard radio button group XOR behavior.
//
AGAGroupsContainer::AGAGroupsContainer()
{
mGroupsArraySize = 0;
mGroups = (AGAGroupMember**) ::NewHandle(0);
this->ExpandArray();
}
AGAGroupsContainer::~AGAGroupsContainer()
{
if (mGroups != NULL)
{
::DisposeHandle((Handle) mGroups);
mGroups = NULL;
}
}
void AGAGroupsContainer::AGAAddGroupMember(MExclusiveObject* groupMember)
{
this->AddGroupMember(groupMember, true);
}
void AGAGroupsContainer::AGARemoveGroupMember(MExclusiveObject* groupMember)
{
// If the supplied object has an ID pair, search for it in the
// members array and zero it out.
if ((mGroups != NULL) && (groupMember->mGroupIDPart1 != kNoGroupID) && (groupMember->mGroupIDPart2 != kNoGroupID))
{
AGAGroupMember* memberPtr;
::HLock((Handle) mGroups);
memberPtr = *mGroups;
for (UInt32 i = 0; i < mGroupsArraySize; i++)
{
if ((memberPtr->mGroupIDPart1 == groupMember->mGroupIDPart1) &&
(memberPtr->mGroupIDPart2 == groupMember->mGroupIDPart2) &&
(memberPtr->mGroupMember == groupMember))
{
memberPtr->mGroupIDPart1 = kNoGroupID;
memberPtr->mGroupIDPart2 = kNoGroupID;
memberPtr->mGroupMember = NULL;
}
memberPtr++;
}
::HUnlock((Handle) mGroups);
}
}
void AGAGroupsContainer::AGAHitGroupMember(MExclusiveObject* groupMember)
{
// If the supplied object has an ID pair, send every other
// member of its group the TurnOff message.
if ((mGroups != NULL) && (groupMember->mGroupIDPart1 != kNoGroupID) && (groupMember->mGroupIDPart2 != kNoGroupID))
{
AGAGroupMember* memberPtr;
::HLock((Handle) mGroups);
memberPtr = *mGroups;
for (UInt32 i = 0; i < mGroupsArraySize; i++)
{
if ((memberPtr->mGroupIDPart1 == groupMember->mGroupIDPart1) &&
(memberPtr->mGroupIDPart2 == groupMember->mGroupIDPart2))
memberPtr->mGroupMember->TurnOff();
memberPtr++;
}
::HUnlock((Handle) mGroups);
}
}
void AGAGroupsContainer::AddGroupMember(MExclusiveObject* groupMember, Boolean allowExpand)
{
// If the supplied object has an ID pair, add it to the
// members array. Try to re-use a zeroed-out entry; if none
// is left, expand the handle by another chunk.
if ((mGroups != NULL) && (groupMember->mGroupIDPart1 != kNoGroupID) && (groupMember->mGroupIDPart2 != kNoGroupID))
{
AGAGroupMember* memberPtr;
Boolean done = false;
::HLock((Handle) mGroups);
memberPtr = *mGroups;
for (UInt32 i = 0; (i < mGroupsArraySize) && ! done; i++)
{
if ((memberPtr->mGroupIDPart1 == kNoGroupID) &&
(memberPtr->mGroupIDPart2 == kNoGroupID))
{
memberPtr->mGroupIDPart1 = groupMember->mGroupIDPart1;
memberPtr->mGroupIDPart2 = groupMember->mGroupIDPart2;
memberPtr->mGroupMember = groupMember;
done = true;
}
memberPtr++;
}
::HUnlock((Handle) mGroups);
if (allowExpand && ! done)
{
this->ExpandArray();
this->AddGroupMember(groupMember, false); // false = recur once only!
}
}
}
void AGAGroupsContainer::ExpandArray()
{
if (mGroups != NULL)
{
::SetHandleSize((Handle) mGroups, (mGroupsArraySize + kGroupArrayChunkSize) * sizeof(AGAGroupMember));
if (::MemError() == noErr)
{
mGroupsArraySize += kGroupArrayChunkSize;
for (UInt32 i = mGroupsArraySize - kGroupArrayChunkSize; i < mGroupsArraySize; i++)
{
(*mGroups)[i].mGroupIDPart1 = kNoGroupID;
(*mGroups)[i].mGroupIDPart2 = kNoGroupID;
(*mGroups)[i].mGroupMember = NULL;
}
}
}
}
//
// MExclusiveObject ---------------------------------------------------------------
//
// This class is a mixin class for objects that can be included in a
// group of mutually exclusively selected objects, i.e. radio buttons
// or icon buttons. When any group member is selected, the others in
// the group are sent the TurnOff message.
//
MExclusiveObject::MExclusiveObject(UInt32 groupIDPart1, UInt32 groupIDPart2)
{
// Construct by setting the ID pair and adding to
// the group.
mGroupIDPart1 = groupIDPart1;
mGroupIDPart2 = groupIDPart2;
gGroupsContainer->AGAAddGroupMember(this);
}
MExclusiveObject::~MExclusiveObject()
{
// Destruct by removing from the group.
gGroupsContainer->AGARemoveGroupMember(this);
}
void MExclusiveObject::SetGroupID(UInt32 groupIDPart1, UInt32 groupIDPart2)
{
gGroupsContainer->AGARemoveGroupMember(this);
mGroupIDPart1 = groupIDPart1;
mGroupIDPart2 = groupIDPart2;
gGroupsContainer->AGAAddGroupMember(this);
}
void MExclusiveObject::TurnOff()
{
// Override as needed.
}
//
// AGAOffscreenImage ------------------------------------------------------------
//
// AGAOffscreenImage holds the data needed to blast a clipped region
// of pixel values onto the current port. This is used by the AGARadioButton
// class to avoid the ultra-tedious pixel-by-pixel drawing of the grayscale
// radio button images.
//
AGAOffscreenImage::AGAOffscreenImage()
{
mImagePixMap = NULL;
mClippingRegion = NULL;
}
AGAOffscreenImage::~AGAOffscreenImage()
{
if (mImagePixMap != NULL)
::DisposePixMap(mImagePixMap);
if (mClippingRegion != NULL)
::DisposeRgn(mClippingRegion);
}
OSErr AGAOffscreenImage::CreateImageData(Point imageSize,
SInt8* imageColorIndexes,
RgnHandle clippingRegion,
const RGBColor* outsideColor)
{
// Allocate an offscreen PixMap to contain the RGB values
// specified.
const UInt32 kImageDepth = 4;
::SetRect(&mImageSourceRect, 0, 0, imageSize.h, imageSize.v);
if (clippingRegion != NULL)
{
// Copy the supplied clipping region.
mClippingRegion = ::NewRgn();
if (mClippingRegion == NULL)
return memFullErr;
::CopyRgn(clippingRegion, mClippingRegion);
OSErr result = ::MemError();
if (result != noErr)
return result;
}
//
// Allocate and set up the PixMap structure.
//
Ptr imagePtr = ::NewPtr(kImageDepth * imageSize.h * imageSize.v);
if (imagePtr == NULL)
return memFullErr;
mImagePixMap = ::NewPixMap();
::HLockHi((Handle) mImagePixMap);
PixMapPtr pixMapPtr = *mImagePixMap;
pixMapPtr->baseAddr = imagePtr;
pixMapPtr->rowBytes = (kImageDepth * imageSize.h) | 0x8000;
pixMapPtr->bounds = mImageSourceRect;
pixMapPtr->pixelType = RGBDirect;
pixMapPtr->pixelSize = 32; // direct 32-bit color values
pixMapPtr->cmpCount = 3; // 3 color components (RGB)
pixMapPtr->cmpSize = 8; // 8 bits per component
pixMapPtr->planeBytes = 0;
if (pixMapPtr->pmTable != NULL)
{
// We're using direct color, so toss the table.
::DisposeCTable(pixMapPtr->pmTable);
pixMapPtr->pmTable = NULL;
}
pixMapPtr->pmReserved = 0;
//
// Finally, set the pixel RGB color values.
//
UInt32* pixelPtr = (UInt32*) imagePtr;
UInt32 numPixels = imageSize.h * imageSize.v;
SInt8* indexPtr = imageColorIndexes;
for (UInt32 pixelIndex = 0; pixelIndex < numPixels; pixelIndex++)
{
SInt8 rampIndex = *indexPtr++;
RGBColor rampColor;
if (rampIndex == OUT)
rampColor = *outsideColor;
else
rampColor = gAGARamp[rampIndex];
//
// Construct 32-bit color value.
// Assuming red is RRrr, blue is BBbb, green is GGgg,
// we want 0x00RRGGBB, using high byte of each color.
// This way we toss the low-order (LSB) color data.
//
UInt32 pixelValue =
((((UInt32) rampColor.red) & 0x0000FF00) << 8) |
(((UInt32) rampColor.green) & 0x0000FF00) |
((((UInt32) rampColor.blue) & 0x0000FF00) >> 8);
*pixelPtr++ = pixelValue;
}
return noErr;
}
void AGAOffscreenImage::DrawImage(SInt16 imageHOrigin, SInt16 imageVOrigin)
{
// Blast the offscreen image data into the current
// port at the specified coordinate location.
RGBColor savedBackColor;
GrafPtr currentPort;
Rect outputRect = mImageSourceRect;
::GetBackColor(&savedBackColor);
// Set to black-on-white before doing CopyBits or our colors may
// be massaged on the way to the screen.
::RGBBackColor(&gAGARamp[rW]);
::RGBForeColor(&gAGARamp[rB]);
::OffsetRect(&outputRect, imageHOrigin, imageVOrigin);
if (mClippingRegion != NULL)
::OffsetRgn(mClippingRegion, imageHOrigin, imageVOrigin);
::GetPort(¤tPort);
::CopyBits((BitMapPtr) *mImagePixMap,
&(currentPort->portBits),
&mImageSourceRect,
&outputRect,
srcCopy,
mClippingRegion);
if (mClippingRegion != NULL)
::OffsetRgn(mClippingRegion, - imageHOrigin, - imageVOrigin);
::RGBBackColor(&savedBackColor);
}
void AGAOffscreenImage::DrawPattern(Rect* imageRect)
{
// Blast the offscreen image data into the current
// port, starting at the specified coordinate location,
// repeating tiled until the imageRect is filled.
RGBColor savedBackColor;
GrafPtr currentPort;
Rect outputRect;
::GetBackColor(&savedBackColor);
::RGBBackColor(&gAGARamp[rW]); // need white BG for desired CopyBits behavior
if (mClippingRegion != NULL)
::OffsetRgn(mClippingRegion, imageRect->left, imageRect->top);
::GetPort(¤tPort);
outputRect.top = imageRect->top;
outputRect.bottom = outputRect.top + mImageSourceRect.bottom;
while (outputRect.top < imageRect->bottom)
{
outputRect.left = imageRect->left;
outputRect.right = outputRect.left + mImageSourceRect.right;
while (outputRect.left < imageRect->right)
{
::CopyBits((BitMapPtr) *mImagePixMap,
&(currentPort->portBits),
&mImageSourceRect,
&outputRect,
srcCopy,
mClippingRegion);
::OffsetRect(&outputRect, mImageSourceRect.right, 0);
}
::OffsetRect(&outputRect, 0, mImageSourceRect.bottom);
}
if (mClippingRegion != NULL)
::OffsetRgn(mClippingRegion, - imageRect->left, - imageRect->top);
::RGBBackColor(&savedBackColor);
}
//
// AGARadioButton ---------------------------------------------------------------
//
// This class implements a standard radio button object,
// with the additional capabilities of automatic handling of
// radio group mutual exclusivity, and mixed state.
//
// Each radio button drawing state has an offscreen image.
AGAOffscreenImage* AGARadioButton::mgOffscreenRadioImages[kNumRadioImages];
// These are the color ramp indexes that are used to build the offscreen images.
SInt8 AGARadioButton::kRadioImageValues[kNumRadioImages][kRadioImageHeight][kRadioImageWidth] =
{
{ // kRadioNormalOff
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
{ OUT, OUT, rB, r10, r2, r2, r2, r4, r11, rB, OUT, OUT },
{ OUT, rB, r4, r2, r1, rW, rW, rW, r2, r7, rB, OUT },
{ r5, r10, r2, r1, rW, rW, r1, r1, r2, r4, r11, r5 },
{ r11, r2, r1, rW, rW, r1, r1, r2, r2, r4, r7, r11 },
{ rB, r2, rW, rW, r1, r1, r2, r2, r4, r4, r7, rB },
{ rB, r2, rW, r1, r1, r2, r2, r4, r4, r5, r7, rB },
{ r11, r4, rW, r1, r2, r2, r4, r4, r5, r5, r7, r11 },
{ r5, r10, r2, r2, r2, r4, r4, r5, r5, r7, r11, r5 },
{ OUT, rB, r7, r4, r4, r4, r5, r5, r7, r7, rB, OUT },
{ OUT, OUT, rB, r10, r7, r7, r7, r7, r11, rB, OUT, OUT },
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
},
{ // kRadioNormalOn
{ OUT, OUT, OUT, r5, r12, rB, rB, r12, r5, OUT, OUT, OUT },
{ OUT, OUT, r12, rB, r11, r10, r10, r10, r11, rB, OUT, OUT },
{ OUT, r12, r11, r10, r8, r8, r8, r7, r7, r6, rB, OUT },
{ r5, rB, r10, r8, rB, rB, rB, rB, r6, r6, r11, r5 },
{ r12, r11, r8, rB, rB, rB, rB, rB, rB, r6, r4, r11 },
{ rB, r10, r8, rB, rB, rB, rB, rB, rB, r4, r4, rB },
{ rB, r10, r8, rB, rB, rB, rB, rB, rB, r4, r2, rB },
{ r12, r10, r7, rB, rB, rB, rB, rB, rB, r2, rW, r11 },
{ r5, r12, r7, r6, rB, rB, rB, rB, r2, rW, r11, r5 },
{ OUT, r12, r6, r6, r6, r4, r4, r2, rW, rW, rB, OUT },
{ OUT, OUT, r12, r11, r4, r4, r2, rW, r11, rB, OUT, OUT },
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
},
{ // kRadioNormalMixed
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
{ OUT, OUT, rB, r10, r2, r2, r2, r4, r11, rB, OUT, OUT },
{ OUT, rB, r4, r2, r1, rW, rW, rW, r2, r7, rB, OUT },
{ r5, r10, r2, r1, rW, rW, r1, r1, r2, r4, r11, r5 },
{ r11, r2, r1, rW, rW, r1, r1, r2, r2, r4, r7, r11 },
{ rB, r2, rW, rB, rB, rB, rB, rB, rB, r4, r7, rB },
{ rB, r2, rW, rB, rB, rB, rB, rB, rB, r5, r7, rB },
{ r11, r4, rW, r1, r2, r2, r4, r4, r5, r5, r7, r11 },
{ r5, r10, r2, r2, r2, r4, r4, r5, r5, r7, r11, r5 },
{ OUT, rB, r7, r4, r4, r4, r5, r5, r7, r7, rB, OUT },
{ OUT, OUT, rB, r10, r7, r7, r7, r7, r11, rB, OUT, OUT },
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
},
{ // kRadioPressedOff
{ OUT, OUT, OUT, r5, r12, rB, rB, r12, r5, OUT, OUT, OUT },
{ OUT, OUT, r12, rB, r11, r11, r11, r11, r11, rB, OUT, OUT },
{ OUT, r12, r11, r11, r10, r10, r9, r9, r9, r8, rB, OUT },
{ r5, rB, r11, r10, r10, r9, r9, r8, r8, r8, r11, r5 },
{ r12, r11, r10, r10, r9, r9, r8, r8, r8, r7, r6, r11 },
{ rB, r11, r10, r9, r9, r8, r8, r8, r7, r7, r6, rB },
{ rB, r11, r9, r9, r8, r8, r8, r7, r7, r6, r6, rB },
{ r12, r11, r9, r8, r8, r8, r7, r7, r6, r6, r4, r11 },
{ r5, r12, r9, r8, r8, r7, r7, r6, r6, r4, r10, r5 },
{ OUT, r11, r8, r8, r7, r7, r6, r6, r4, r4, rB, OUT },
{ OUT, OUT, r12, r11, r6, r6, r6, r4, r10, rB, OUT, OUT },
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
},
{ // kRadioPressedOn
{ OUT, OUT, OUT, r5, r12, rB, rB, r12, r5, OUT, OUT, OUT },
{ OUT, OUT, r12, rB, r11, r11, r11, r11, r11, rB, OUT, OUT },
{ OUT, r12, r11, r11, r10, r10, r9, r9, r9, r8, rB, OUT },
{ r5, rB, r11, r10, rB, rB, rB, rB, r8, r8, r11, r5 },
{ r12, r11, r10, rB, rB, rB, rB, rB, rB, r7, r6, r11 },
{ rB, r11, r10, rB, rB, rB, rB, rB, rB, r7, r6, rB },
{ rB, r11, r9, rB, rB, rB, rB, rB, rB, r6, r6, rB },
{ r12, r11, r9, rB, rB, rB, rB, rB, rB, r6, r4, r11 },
{ r5, r12, r9, r8, rB, rB, rB, rB, r6, r4, r10, r5 },
{ OUT, r11, r8, r8, r7, r7, r6, r6, r4, r4, rB, OUT },
{ OUT, OUT, r12, r11, r6, r6, r6, r4, r10, rB, OUT, OUT },
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
},
{ // kRadioPressedMixed
{ OUT, OUT, OUT, r5, r12, rB, rB, r12, r5, OUT, OUT, OUT },
{ OUT, OUT, r12, rB, r11, r11, r11, r11, r11, rB, OUT, OUT },
{ OUT, r12, r11, r11, r10, r10, r9, r9, r9, r8, rB, OUT },
{ r5, rB, r11, r10, r10, r9, r9, r8, r8, r8, r11, r5 },
{ r12, r11, r10, r10, r9, r9, r8, r8, r8, r7, r6, r11 },
{ rB, r11, r10, rB, rB, rB, rB, rB, rB, r7, r6, rB },
{ rB, r11, r9, rB, rB, rB, rB, rB, rB, r6, r6, rB },
{ r12, r11, r9, r8, r8, r8, r7, r7, r6, r6, r4, r11 },
{ r5, r12, r9, r8, r8, r7, r7, r6, r6, r4, r10, r5 },
{ OUT, r11, r8, r8, r7, r7, r6, r6, r4, r4, rB, OUT },
{ OUT, OUT, r12, r11, r6, r6, r6, r4, r10, rB, OUT, OUT },
{ OUT, OUT, OUT, r5, r11, rB, rB, r11, r5, OUT, OUT, OUT },
},
{ // kRadioDisabledOff
{ OUT, OUT, OUT, r4, r7, r7, r7, r7, r4, OUT, OUT, OUT },
{ OUT, OUT, r7, r7, r3, r2, r2, r3, r7, r7, OUT, OUT },
{ OUT, r7, r3, r2, r2, r2, r2, r2, r2, r3, r7, OUT },
{ r4, r7, r2, r2, r2, r2, r2, r2, r2, r2, r7, r4 },
{ r7, r3, r2, r2, r2, r2, r2, r2, r2, r2, r3, r7 },
{ r7, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r7 },
{ r7, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r7 },
{ r7, r3, r2, r2, r2, r2, r2, r2, r2, r2, r3, r7 },
{ r4, r7, r2, r2, r2, r2, r2, r2, r2, r2, r7, r4 },
{ OUT, r7, r3, r2, r2, r2, r2, r2, r2, r3, r7, OUT },
{ OUT, OUT, r7, r7, r3, r2, r2, r3, r7, r7, OUT, OUT },
{ OUT, OUT, OUT, r4, r7, r7, r7, r7, r4, OUT, OUT, OUT },
},
{ // kRadioDisabledOn
{ OUT, OUT, OUT, r4, r7, r7, r7, r7, r4, OUT, OUT, OUT },
{ OUT, OUT, r7, r7, r4, r4, r4, r4, r7, r7, OUT, OUT },
{ OUT, r7, r5, r4, r4, r4, r4, r4, r4, r5, r7, OUT },
{ r4, r7, r4, r4, r8, r8, r8, r8, r4, r4, r7, r4 },
{ r7, r4, r4, r8, r8, r8, r8, r8, r8, r4, r4, r7 },
{ r7, r4, r4, r8, r8, r8, r8, r8, r8, r4, r4, r7 },
{ r7, r4, r4, r8, r8, r8, r8, r8, r8, r4, r4, r7 },
{ r7, r4, r4, r8, r8, r8, r8, r8, r8, r4, r4, r7 },
{ r4, r7, r4, r4, r8, r8, r8, r8, r4, r4, r7, r4 },
{ OUT, r7, r5, r4, r4, r4, r4, r4, r4, r5, r7, OUT },
{ OUT, OUT, r7, r7, r4, r4, r4, r4, r7, r7, OUT, OUT },
{ OUT, OUT, OUT, r4, r7, r7, r7, r7, r4, OUT, OUT, OUT },
},
{ // kRadioDisabledMixed
{ OUT, OUT, OUT, r4, r7, r7, r7, r7, r4, OUT, OUT, OUT },
{ OUT, OUT, r7, r7, r3, r2, r2, r3, r7, r7, OUT, OUT },
{ OUT, r7, r3, r2, r2, r2, r2, r2, r2, r3, r7, OUT },
{ r4, r7, r2, r2, r2, r2, r2, r2, r2, r2, r7, r4 },
{ r7, r3, r2, r2, r2, r2, r2, r2, r2, r2, r3, r7 },
{ r7, r2, r2, r8, r8, r8, r8, r8, r8, r2, r2, r7 },
{ r7, r2, r2, r8, r8, r8, r8, r8, r8, r2, r2, r7 },
{ r7, r3, r2, r2, r2, r2, r2, r2, r2, r2, r3, r7 },
{ r4, r7, r2, r2, r2, r2, r2, r2, r2, r2, r7, r4 },
{ OUT, r7, r3, r2, r2, r2, r2, r2, r2, r3, r7, OUT },
{ OUT, OUT, r7, r7, r3, r2, r2, r3, r7, r7, OUT, OUT },
{ OUT, OUT, OUT, r4, r7, r7, r7, r7, r4, OUT, OUT, OUT },
}
};
OSErr AGARadioButton::AllocateRadioImages()
{
// Allocate the offscreen image for each radio button state.
OSErr result = noErr;
Point imageSize;
imageSize.h = kRadioImageWidth;
imageSize.v = kRadioImageHeight;
// A simple round rect defines the radio image clipping region.
RgnHandle radioImageClippingRegion = ::NewRgn();
if (radioImageClippingRegion == NULL)
result = memFullErr;
else
{
Rect imageClippingRect;
::SetRect(&imageClippingRect, 0, 0, kRadioImageWidth, kRadioImageHeight);
::OpenRgn();
::FrameRoundRect(&imageClippingRect, 11, 11);
//::FrameOval(&imageClippingRect); ugly AGA 7/96 specs use just the chunky circle -- we'll stick with earlier specs
::CloseRgn(radioImageClippingRegion);
}
for (UInt32 imageIndex = 0; imageIndex < kNumRadioImages; imageIndex++)
{
if (result == noErr)
{
mgOffscreenRadioImages[imageIndex] = new AGAOffscreenImage;
result = mgOffscreenRadioImages[imageIndex]->CreateImageData(
imageSize,
&kRadioImageValues[imageIndex][0][0],
radioImageClippingRegion,
&gAGARamp[rB]);
}
}
if (radioImageClippingRegion != NULL)
::DisposeRgn(radioImageClippingRegion);
return result;
}
void AGARadioButton::DisposeRadioImages()
{
for (UInt32 imageIndex = 0; imageIndex < kNumRadioImages; imageIndex++)
if (mgOffscreenRadioImages[imageIndex] != NULL)
delete mgOffscreenRadioImages[imageIndex];
}
AGARadioButton::AGARadioButton(Rect* bounds, const AGATextStyle& textStyle, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
: AGAObject(bounds), MExclusiveObject(groupIDPart1, groupIDPart2)
{
// Construct with initial empty button title.
mValue = kRadioButtonOff;
mAutomaticState = automaticState;
mTitle[0];
mTextStyle = textStyle;
}
AGARadioButton::AGARadioButton(Rect* bounds, const AGATextStyle& textStyle, StringPtr title, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
: AGAObject(bounds), MExclusiveObject(groupIDPart1, groupIDPart2)
{
// Construct with specified button title.
mValue = kRadioButtonOff;
mAutomaticState = automaticState;
AGA_PLstrcpy(mTitle, title);
mTextStyle = textStyle;
}
AGARadioButton::AGARadioButton(Rect* bounds, const AGATextStyle& textStyle, SInt16 stringListResourceID, SInt16 stringIndex, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
: AGAObject(bounds), MExclusiveObject(groupIDPart1, groupIDPart2)
{
// Construct by getting button title from specified resource.
mValue = kRadioButtonOff;
mAutomaticState = automaticState;
::GetIndString(mTitle, stringListResourceID, stringIndex);
mTextStyle = textStyle;
}
AGARadioButton::~AGARadioButton()
{
}
void AGARadioButton::DrawObject()
{
// Draw button in normal unpressed state.
this->DrawButton(kNotPressed);
}
Boolean AGARadioButton::TrackMouse(Point mouseLocation)
{
// If inherited tracking succeeded and we are set to
// automatically change our state, toggle it.
Boolean wasItHit = AGAObject::TrackMouse(mouseLocation);
if (wasItHit && mAutomaticState)
this->SetValue(kRadioButtonOn, kRedraw);
return wasItHit;
}
void AGARadioButton::SetTitle(StringPtr title, Boolean redraw)
{
// Change button title, redraw if specified.
AGA_PLstrcpy(mTitle, title);
if (redraw)
this->DrawObject();
}
SInt32 AGARadioButton::GetValue()
{
// Return current state.
return mValue;
}
void AGARadioButton::SetValue(SInt32 newValue, Boolean redraw)
{
// Set current state, redraw if specified and necessary.
if (newValue == kRadioButtonOn)
gGroupsContainer->AGAHitGroupMember(this);
if (newValue != mValue)
{
mValue = newValue;
if (redraw)
{
this->DrawButton(kNotPressed);
}
}
}
void AGARadioButton::SetGroupID(UInt32 groupIDPart1, UInt32 groupIDPart2)
{
MExclusiveObject::SetGroupID(groupIDPart1, groupIDPart2);
// If we are being installed into a group, we should turn automatic
// mode on.
if ((groupIDPart1 != kNoGroupID) && (groupIDPart2 != kNoGroupID))
mAutomaticState = true;
}
void AGARadioButton::TurnOff()
{
// Turn off the radio button, presumably in response
// to another button in the group being turned on.
this->SetValue(kRadioButtonOff, kRedraw);
}
void AGARadioButton::DrawButton(Boolean pressed)
{
AGADrawingEnvironment env;
// Draw the button in the appropriate state.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (! mEnabled)
this->DrawButtonDisabled(deep);
else if (pressed)
this->DrawButtonPressed(deep);
else
this->DrawButtonNormal(deep);
}
}
void AGARadioButton::SetTrackingState(Boolean isIn)
{
// Draw the button pressed or unpressed as specified.
this->DrawButton(isIn);
}
void AGARadioButton::DrawButtonNormal(Boolean deep)
{
Rect r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
// Draw the button in enabled/unpressed state.
if (deep)
{
if (mValue == kRadioButtonMixed)
this->CopyImage(kRadioNormalMixed);
else if (mValue == kRadioButtonOn)
this->CopyImage(kRadioNormalOn);
else
this->CopyImage(kRadioNormalOff);
}
else
{
r.right = r.left + kRadioImageWidth;
r.bottom = r.top + kRadioImageHeight;
// Paint white over previous junk, if any.
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
// Paint frame.
::RGBForeColor(&gAGARamp[rB]);
::FrameOval(&r);
// Draw dot or dash.
if (mValue == kRadioButtonOn)
{
::InsetRect(&r, 3, 3);
::PaintRoundRect(&r, 4, 4);
}
else if (mValue == kRadioButtonMixed)
{
::PenSize(1, 2);
::MoveTo(r.left + 3, r.top + 5);
::Line(5, 0);
}
::PenNormal();
}
// Draw the title.
r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.left += (kRadioImageWidth + 4);
r.bottom = r.top + kRadioImageHeight;
AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
}
void AGARadioButton::DrawButtonPressed(Boolean deep)
{
Rect r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
// Draw the button in enabled/pressed state.
if (deep)
{
if (mValue == kRadioButtonMixed)
this->CopyImage(kRadioPressedMixed);
else if (mValue == kRadioButtonOn)
this->CopyImage(kRadioPressedOn);
else
this->CopyImage(kRadioPressedOff);
}
else
{
r.right = r.left + kRadioImageWidth;
r.bottom = r.top + kRadioImageHeight;
// Paint white over previous junk, if any.
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
// Paint frame.
::RGBForeColor(&gAGARamp[rB]);
::PenSize(2, 2);
::FrameOval(&r);
// Draw dot or dash.
if (mValue == kRadioButtonOn)
{
::InsetRect(&r, 3, 3);
::PaintRoundRect(&r, 4, 4);
}
else if (mValue == kRadioButtonMixed)
{
::PenSize(1, 2);
::MoveTo(r.left + 3, r.top + 5);
::Line(5, 0);
}
::PenNormal();
}
// Draw the title.
r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.left += (kRadioImageWidth + 4);
r.bottom = r.top + kRadioImageHeight;
AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
}
void AGARadioButton::DrawButtonDisabled(Boolean deep)
{
Rect r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
// Draw the button in disabled/unpressed state.
if (deep)
{
if (mValue == kRadioButtonMixed)
this->CopyImage(kRadioDisabledMixed);
else if (mValue == kRadioButtonOn)
this->CopyImage(kRadioDisabledOn);
else
this->CopyImage(kRadioDisabledOff);
}
else
{
r.right = r.left + kRadioImageWidth;
r.bottom = r.top + kRadioImageHeight;
// Paint white over previous junk, if any.
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
// Paint frame.
::PenPat(&qd.gray);
::RGBForeColor(&gAGARamp[rB]);
::FrameOval(&r);
// Draw check or dash.
if (mValue == kRadioButtonOn)
{
::InsetRect(&r, 3, 3);
::PaintRoundRect(&r, 4, 4);
}
else if (mValue == kRadioButtonMixed)
{
::PenSize(1, 2);
::MoveTo(r.left + 3, r.top + 5);
::Line(5, 0);
}
::PenNormal();
}
// Draw the title.
r = mBounds;
::OffsetRect(&r, 2, 2); // visually match the system CDEF
r.left += (kRadioImageWidth + 4);
r.bottom = r.top + kRadioImageHeight;
AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kDisabledOutput, deep, mTextStyle);
}
void AGARadioButton::CopyImage(UInt32 index)
{
// Blast the specified offscreen image into the
// radio button's button area. We offset by (2, 2)
// to match the positioning of the system CDEF.
mgOffscreenRadioImages[index]->DrawImage(mBounds.left + 2, mBounds.top + 2);
}
//
// MIconButtonObject ---------------------------------------------------------------
//
// This mixin class handles button drawing for the different types
// of icon button classes. This class draws the button, and subclasses
// for push/radio/checkbox that mix it in handle the behavioral aspects.
//
// Ideal button sizes, to match AGA specification:
// - Large icon button: 40x40 (32x32 iclx plus 4 pixel border on each side)
// - Small icon button: 22x22 (16x16 icsx plus 3 pixel border on each side)
// - Mini icon button: 16x16 (12x12 icmx plus 2 pixel border on each side)
// Note that mini icons are a rather rare resource that ResEdit 2.x doesn't grok.
//
MIconButtonObject::MIconButtonObject()
{
// Construct with no icon IDs.
mOffIconID = kNoIconID;
mOnIconID = kNoIconID;
mFrameType = kAutoFrame;
mImageType = kAutoIconFamily;
}
MIconButtonObject::MIconButtonObject(SInt16 offIconID, SInt16 onIconID, ButtonFrameType frameType, ButtonImageType imageType)
{
// Construct with specified icon IDs.
mOffIconID = offIconID;
mOnIconID = onIconID;
mFrameType = frameType;
mImageType = imageType;
}
MIconButtonObject::~MIconButtonObject()
{
}
void MIconButtonObject::SetIconIDs(SInt16 offIconID, SInt16 onIconID)
{
// Set icon IDs as specified.
mOffIconID = offIconID;
mOnIconID = onIconID;
}
void MIconButtonObject::SetFrameType(ButtonFrameType frameType)
{
// Set button frame type as specified.
mFrameType = frameType;
}
void MIconButtonObject::SetImageType(ButtonImageType imageType)
{
// Set buttom image type as specified.
mImageType = imageType;
}
void MIconButtonObject::DrawIconButton(Rect* bounds,
Boolean isOn,
Boolean isPressed,
Boolean isEnabled,
Boolean deep)
{
// Draw the icon button in the appropriate state.
Rect r = *bounds;
//
// Draw the blank button with the appropriate frame type.
//
ButtonFrameType frameType = mFrameType;
if (frameType == kAutoFrame)
frameType = MIconButtonObject::GetDefaultFrameType(r.right - r.left);
if (deep)
{
if (frameType == kMiniFrame)
this->DrawMiniEdges(bounds, isOn, isPressed, isEnabled);
else if (frameType == kSmallFrame)
this->DrawSmallEdges(bounds, isOn, isPressed, isEnabled);
else
this->DrawLargeEdges(bounds, isOn, isPressed, isEnabled);
}
else
{
if (isPressed || isOn)
::RGBForeColor(&gAGARamp[rB]);
else
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
if (! isEnabled)
::PenPat(&qd.gray);
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
::PenNormal();
}
//
// Determine the target area into which the image must
// be drawn.
//
ButtonImageType imageType = mImageType;
Point imageSize;
Point imageCenter;
SInt16 imageResourceID = isOn ? mOnIconID : mOffIconID;
PicHandle pictureHandle;
CIconHandle colorIconHandle;
imageCenter.h = r.left + ((r.right - r.left) / 2);
imageCenter.v = r.top + ((r.bottom - r.top) / 2);
if (imageType == kAutoIconFamily)
imageType = MIconButtonObject::GetDefaultImageType(r.right - r.left);
switch (imageType)
{
case kPictureIcon:
pictureHandle = this->GetPictureImage(&imageSize, imageResourceID);
break;
case kColorIcon:
colorIconHandle = this->GetColorIconImage(&imageSize, imageResourceID);
break;
case kMiniIcon:
::SetPt(&imageSize, 12, 12); // 12x12 icm#
break;
case kSmallIcon:
::SetPt(&imageSize, 16, 16); // 16x16 ics#
break;
case kLargeIcon:
default:
::SetPt(&imageSize, 32, 32); // 32x32 icl#
break;
}
r.left = imageCenter.h - (imageSize.h / 2);
r.right = r.left + imageSize.h;
r.top = imageCenter.v - (imageSize.v / 2);
r.bottom = r.top + imageSize.v;
//
// Draw the image onto the blank button.
//
IconTransformType aTransform = isPressed ? ttSelected : (isEnabled ? ttNone : ttDisabled);
if (imageResourceID != kNoIconID)
{
::RGBForeColor(&gAGARamp[rB]);
switch (imageType)
{
case kPictureIcon:
if (pictureHandle != NULL)
{
::DrawPicture(pictureHandle, &r);
// The PicHandle is not explicitly released. Just let it get purged as needed.
}
break;
case kColorIcon:
if (colorIconHandle != NULL)
{
(void) ::PlotCIconHandle(&r, atNone, aTransform, colorIconHandle);
::DisposeCIcon(colorIconHandle);
}
break;
case kMiniIcon:
case kSmallIcon:
case kLargeIcon:
default:
(void) ::PlotIconID(&r, atNone, aTransform, imageResourceID);
break;
}
}
}
void MIconButtonObject::DrawMiniEdges(Rect* bounds, Boolean isOn, Boolean isPressed, Boolean isEnabled)
{
// Draw the button edges as specified for a
// "mini" sized button.
enum { TLFrame, TLInner, BRFrame, BRInner, CornerFrame, CornerInner, Fill, kNumEdgeColors };
UInt8 colorIndexes[kNumEdgeColors];
Rect r = *bounds;
if (isPressed)
{
colorIndexes[TLFrame] = rA2;
colorIndexes[BRFrame] = r11;
colorIndexes[CornerFrame] = r12;
colorIndexes[TLInner] = r10;
colorIndexes[BRInner] = r5;
colorIndexes[CornerInner] = r8;
colorIndexes[Fill] = r7;
}
else if (isEnabled)
{
colorIndexes[TLFrame] = isOn ? rA2 : r9;
colorIndexes[BRFrame] = isOn ? r11 : rA1;
colorIndexes[CornerFrame] = isOn ? r12 : r10;
colorIndexes[TLInner] = isOn ? r10 : rW;
colorIndexes[BRInner] = isOn ? r5 : r7;
colorIndexes[CornerInner] = isOn ? r8 : r3;
colorIndexes[Fill] = isOn ? r7 : r3;
}
else // disabled
{
colorIndexes[TLFrame] = isOn ? r8 : r5;
colorIndexes[BRFrame] = r6;
colorIndexes[CornerFrame] = isOn ? r7 : r5;
colorIndexes[TLInner] = isOn ? r4 : r2;
colorIndexes[BRInner] = isOn ? r4 : r2;
colorIndexes[CornerInner] = isOn ? r4 : r2;
colorIndexes[Fill] = isOn ? r4 : r2;
}
// Draw the outer frame.
::RGBForeColor(&gAGARamp[colorIndexes[TLFrame]]);
::MoveTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::LineTo(r.right - 1, r.top);
::RGBForeColor(&gAGARamp[colorIndexes[CornerFrame]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRFrame]]);
::Move(0, 1);
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.left, r.bottom - 1);
::RGBForeColor(&gAGARamp[colorIndexes[CornerFrame]]);
::Line(0, 0);
// Draw the 1st pixel of shading.
::RGBForeColor(&gAGARamp[colorIndexes[TLInner]]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 2, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRInner]]);
::Move(0, 1);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 1, r.bottom - 2);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner]]);
::Line(0, 0);
// Fill the interior.
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::InsetRect(&r, 2, 2);
::PaintRect(&r);
::InsetRect(&r, -2, -2);
}
void MIconButtonObject::DrawSmallEdges(Rect* bounds, Boolean isOn, Boolean isPressed, Boolean isEnabled)
{
// Draw the button edges as specified for a
// "small" sized button.
enum { TLFrame, TLInner1, TLInner2, BRFrame, BRInner1, BRInner2, CornerFrame, CornerInner1, CornerInner2, Fill, kNumEdgeColors };
UInt8 colorIndexes[kNumEdgeColors];
Rect r = *bounds;
if (isPressed)
{
colorIndexes[TLFrame] = rA2;
colorIndexes[BRFrame] = r11;
colorIndexes[CornerFrame] = rA2;
colorIndexes[TLInner1] = r11;
colorIndexes[BRInner1] = r4;
colorIndexes[CornerInner1] = r8;
colorIndexes[TLInner2] = r9;
colorIndexes[BRInner2] = r6;
colorIndexes[CornerInner2] = r7;
colorIndexes[Fill] = r7;
}
else if (isEnabled)
{
colorIndexes[TLFrame] = isOn ? rA2 : r9;
colorIndexes[BRFrame] = isOn ? r11 : rA1;
colorIndexes[CornerFrame] = isOn ? rA2 : r9;
colorIndexes[TLInner1] = isOn ? r11 : r3;
colorIndexes[BRInner1] = isOn ? r4 : r8;
colorIndexes[CornerInner1] = isOn ? r8 : r5;
colorIndexes[TLInner2] = isOn ? r9 : rW;
colorIndexes[BRInner2] = r6;
colorIndexes[CornerInner2] = isOn ? r7 : r3;
colorIndexes[Fill] = isOn ? r7 : r3;
}
else // disabled
{
colorIndexes[TLFrame] = isOn ? r8 : r5;
colorIndexes[BRFrame] = r6;
colorIndexes[CornerFrame] = isOn ? r8 : r5;
colorIndexes[TLInner1] = isOn ? r4 : r2;
colorIndexes[BRInner1] = isOn ? r4 : r2;
colorIndexes[CornerInner1] = isOn ? r4 : r2;
colorIndexes[TLInner2] = isOn ? r4 : r2;
colorIndexes[BRInner2] = isOn ? r4 : r2;
colorIndexes[CornerInner2] = isOn ? r4 : r2;
colorIndexes[Fill] = isOn ? r4 : r2;
}
// Draw the outer frame.
::RGBForeColor(&gAGARamp[colorIndexes[TLFrame]]);
::MoveTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::LineTo(r.right - 1, r.top);
::RGBForeColor(&gAGARamp[colorIndexes[CornerFrame]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRFrame]]);
::Move(0, 1);
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.left, r.bottom - 1);
::RGBForeColor(&gAGARamp[colorIndexes[CornerFrame]]);
::Line(0, 0);
// Draw the 1st pixel of shading.
::RGBForeColor(&gAGARamp[colorIndexes[TLInner1]]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 2, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner1]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRInner1]]);
::Move(0, 1);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 1, r.bottom - 2);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner1]]);
::Line(0, 0);
// Draw the 2nd pixel of shading.
::RGBForeColor(&gAGARamp[colorIndexes[TLInner2]]);
::MoveTo(r.left + 2, r.bottom - 4);
::LineTo(r.left + 2, r.top + 2);
::LineTo(r.right - 3, r.top + 2);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner2]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRInner2]]);
::Move(0, 1);
::LineTo(r.right - 3, r.bottom - 3);
::LineTo(r.left + 2, r.bottom - 3);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner2]]);
::Line(0, 0);
// Fill the interior.
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::InsetRect(&r, 3, 3);
::PaintRect(&r);
::InsetRect(&r, -3, -3);
}
void MIconButtonObject::DrawLargeEdges(Rect* bounds, Boolean isOn, Boolean isPressed, Boolean isEnabled)
{
// Draw the button edges as specified for a
// "large" sized button.
enum { TLFrame, TLInner1, TLInner2, TLInner3, BRFrame, BRInner1, BRInner2, BRInner3, CornerFrame, CornerInner1, CornerInner2, CornerInner3, Fill, kNumEdgeColors };
UInt8 colorIndexes[kNumEdgeColors];
Rect r = *bounds;
if (isPressed)
{
colorIndexes[TLFrame] = rA2;
colorIndexes[BRFrame] = r11;
colorIndexes[CornerFrame] = r12;
colorIndexes[TLInner1] = rA1;
colorIndexes[BRInner1] = r4;
colorIndexes[CornerInner1] = r11;
colorIndexes[TLInner2] = r11;
colorIndexes[BRInner2] = r5;
colorIndexes[CornerInner2] = r8;
colorIndexes[TLInner3] = r9;
colorIndexes[BRInner3] = r6;
colorIndexes[CornerInner3] = r7;
colorIndexes[Fill] = r7;
}
else if (isEnabled)
{
colorIndexes[TLFrame] = isOn ? rA2 : r9;
colorIndexes[BRFrame] = isOn ? r11 : rA1;
colorIndexes[CornerFrame] = isOn ? r12 : r10;
colorIndexes[TLInner1] = isOn ? rA1 : r3;
colorIndexes[BRInner1] = isOn ? r4 : r10;
colorIndexes[CornerInner1] = isOn ? r11 : r5;
colorIndexes[TLInner2] = isOn ? r11 : r1;
colorIndexes[BRInner2] = isOn ? r5 : r8;
colorIndexes[CornerInner2] = isOn ? r8 : r4;
colorIndexes[TLInner3] = isOn ? r9 : rW;
colorIndexes[BRInner3] = r6;
colorIndexes[CornerInner3] = isOn ? r7 : r3;
colorIndexes[Fill] = isOn ? r7 : r3;
}
else // disabled
{
colorIndexes[TLFrame] = isOn ? r8 : r5;
colorIndexes[BRFrame] = isOn ? r6 : r7;
colorIndexes[CornerFrame] = isOn ? r7 : r6;
colorIndexes[TLInner1] = isOn ? r4 : r2;
colorIndexes[BRInner1] = isOn ? r4 : r2;
colorIndexes[CornerInner1] = isOn ? r4 : r2;
colorIndexes[TLInner2] = isOn ? r4 : r2;
colorIndexes[BRInner2] = isOn ? r4 : r2;
colorIndexes[CornerInner2] = isOn ? r4 : r2;
colorIndexes[TLInner3] = isOn ? r4 : r2;
colorIndexes[BRInner3] = isOn ? r4 : r2;
colorIndexes[CornerInner3] = isOn ? r4 : r2;
colorIndexes[Fill] = isOn ? r4 : r2;
}
// Draw the outer frame.
::RGBForeColor(&gAGARamp[colorIndexes[TLFrame]]);
::MoveTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::LineTo(r.right - 1, r.top);
::RGBForeColor(&gAGARamp[colorIndexes[CornerFrame]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRFrame]]);
::Move(0, 1);
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.left, r.bottom - 1);
::RGBForeColor(&gAGARamp[colorIndexes[CornerFrame]]);
::Line(0, 0);
// Draw the 1st pixel of shading.
::RGBForeColor(&gAGARamp[colorIndexes[TLInner1]]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 2, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner1]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRInner1]]);
::Move(0, 1);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 1, r.bottom - 2);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner1]]);
::Line(0, 0);
// Draw the 2nd pixel of shading.
::RGBForeColor(&gAGARamp[colorIndexes[TLInner2]]);
::MoveTo(r.left + 2, r.bottom - 4);
::LineTo(r.left + 2, r.top + 2);
::LineTo(r.right - 3, r.top + 2);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner2]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRInner2]]);
::Move(0, 1);
::LineTo(r.right - 3, r.bottom - 3);
::LineTo(r.left + 2, r.bottom - 3);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner2]]);
::Line(0, 0);
// Draw the 3rd pixel of shading.
::RGBForeColor(&gAGARamp[colorIndexes[TLInner3]]);
::MoveTo(r.left + 3, r.bottom - 5);
::LineTo(r.left + 3, r.top + 3);
::LineTo(r.right - 4, r.top + 3);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner3]]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[BRInner3]]);
::Move(0, 1);
::LineTo(r.right - 4, r.bottom - 4);
::LineTo(r.left + 3, r.bottom - 4);
::RGBForeColor(&gAGARamp[colorIndexes[CornerInner3]]);
::Line(0, 0);
// Fill the interior.
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::InsetRect(&r, 4, 4);
::PaintRect(&r);
::InsetRect(&r, -4, -4);
}
PicHandle MIconButtonObject::GetPictureImage(Point* imageSize, SInt16 pictureResourceID)
{
PicHandle pictureHandle = ::GetPicture(pictureResourceID);
if (pictureHandle != NULL)
{
Rect frame = (**pictureHandle).picFrame;
::SetPt(imageSize, frame.right - frame.left, frame.bottom - frame.top);
}
return pictureHandle;
}
CIconHandle MIconButtonObject::GetColorIconImage(Point* imageSize, SInt16 cicnResourceID)
{
CIconHandle colorIconHandle = ::GetCIcon(cicnResourceID);
if (colorIconHandle != NULL)
{
Rect frame = (**colorIconHandle).iconBMap.bounds;
::SetPt(imageSize, frame.right - frame.left, frame.bottom - frame.top);
}
return colorIconHandle;
}
MIconButtonObject::ButtonFrameType MIconButtonObject::GetDefaultFrameType(SInt16 buttonWidth)
{
if (buttonWidth > 39)
return kLargeFrame;
else if (buttonWidth > 21)
return kSmallFrame;
else
return kMiniFrame;
}
MIconButtonObject::ButtonImageType MIconButtonObject::GetDefaultImageType(SInt16 buttonWidth)
{
if (buttonWidth > 39)
return kLargeIcon;
else if (buttonWidth > 21)
return kSmallIcon;
else
return kMiniIcon;
}
//
// AGAIconPushButton ---------------------------------------------------------------
//
// This class implements an icon-based pushbutton object, such as
// a toolbar icon command button.
//
AGAIconPushButton::AGAIconPushButton(Rect* bounds)
: AGAPushButton(bounds, gAGAStdSystemStyle), MIconButtonObject()
{
// Just call through to mixed in constructors.
}
AGAIconPushButton::AGAIconPushButton(Rect* bounds, SInt16 iconID, ButtonFrameType frameType, ButtonImageType imageType)
: AGAPushButton(bounds, gAGAStdSystemStyle), MIconButtonObject(iconID, iconID, frameType, imageType)
{
// Just call through to mixed in constructors.
}
AGAIconPushButton::~AGAIconPushButton()
{
}
void AGAIconPushButton::DrawButtonNormal(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, false, kNotPressed, kEnabled, deep);
}
void AGAIconPushButton::DrawButtonPressed(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, false, kPressed, kEnabled, deep);
}
void AGAIconPushButton::DrawButtonDisabled(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, false, kNotPressed, kDisabled, deep);
}
//
// AGAIconCheckBox ---------------------------------------------------------------
//
// This class implements an icon-based checkbox object, such as
// a toolbar icon on/off button.
//
AGAIconCheckBox::AGAIconCheckBox(Rect* bounds, Boolean automaticState)
: AGACheckBox(bounds, gAGAStdSystemStyle, automaticState), MIconButtonObject()
{
// Just call through to mixed in constructors.
}
AGAIconCheckBox::AGAIconCheckBox(Rect* bounds, Boolean automaticState, SInt16 offIconID, SInt16 onIconID, ButtonFrameType frameType, ButtonImageType imageType)
: AGACheckBox(bounds, gAGAStdSystemStyle, automaticState), MIconButtonObject(offIconID, onIconID, frameType, imageType)
{
// Just call through to mixed in constructors.
}
AGAIconCheckBox::~AGAIconCheckBox()
{
}
void AGAIconCheckBox::DrawButtonNormal(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, mValue != kCheckBoxOff, kNotPressed, kEnabled, deep);
}
void AGAIconCheckBox::DrawButtonPressed(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, mValue != kCheckBoxOff, kPressed, kEnabled, deep);
}
void AGAIconCheckBox::DrawButtonDisabled(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, mValue != kCheckBoxOff, kNotPressed, kDisabled, deep);
}
//
// AGAIconRadioButton ---------------------------------------------------------------
//
// This class implements an icon-based pushbutton object, such as
// a toolbar icon XOR group member button.
//
AGAIconRadioButton::AGAIconRadioButton(Rect* bounds, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
: AGARadioButton(bounds, gAGAStdSystemStyle, groupIDPart1, groupIDPart2, automaticState), MIconButtonObject()
{
// Just call through to mixed in constructors.
}
AGAIconRadioButton::AGAIconRadioButton(Rect* bounds, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState, SInt16 offIconID, SInt16 onIconID, ButtonFrameType frameType, ButtonImageType imageType)
: AGARadioButton(bounds, gAGAStdSystemStyle, groupIDPart1, groupIDPart2, automaticState), MIconButtonObject(offIconID, onIconID, frameType, imageType)
{
// Just call through to mixed in constructors.
}
AGAIconRadioButton::~AGAIconRadioButton()
{
}
void AGAIconRadioButton::DrawButtonNormal(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, mValue != kRadioButtonOff, kNotPressed, kEnabled, deep);
}
void AGAIconRadioButton::DrawButtonPressed(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, mValue != kRadioButtonOff, kPressed, kEnabled, deep);
}
void AGAIconRadioButton::DrawButtonDisabled(Boolean deep)
{
// Call icon button parent class with appropriate parameters.
MIconButtonObject::DrawIconButton(&mBounds, mValue != kRadioButtonOff, kNotPressed, kDisabled, deep);
}
//
// AGATrackingIndicator ---------------------------------------------------------------
//
// This is the abstract superclass for scroll bars and sliders.
// They all have a range, and a value shown by a draggable indicator.
//
#pragma segment GrayCouncilCore2
AGATrackingIndicator::AGATrackingIndicator(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue)
: AGAObject(bounds)
{
// Construct with default options.
mMinimum = minimum;
mMaximum = maximum;
mValue = initialValue;
mPageSize = 1;
mGhostValue = mValue;
mLiveTracking = false;
mIsProportional = false;
mIsHorizontal = (bounds->right - bounds->left) > (bounds->bottom - bounds->top);
mIsPressed = false;
mNotificationRoutine = NULL;
}
AGATrackingIndicator::AGATrackingIndicator(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, SInt32 pageSize, Boolean liveTracking, Boolean proportional)
: AGAObject(bounds)
{
// Construct with specified options.
mMinimum = minimum;
mMaximum = maximum;
mValue = initialValue;
mPageSize = pageSize;
mGhostValue = mValue;
mLiveTracking = liveTracking;
mIsProportional = proportional;
mIsHorizontal = (bounds->right - bounds->left) > (bounds->bottom - bounds->top);
mIsPressed = false;
mNotificationRoutine = NULL;
}
AGATrackingIndicator::~AGATrackingIndicator()
{
}
void AGATrackingIndicator::InstallNotificationRoutine(AGATrackingIndicatorNotifyPtr notificationRoutine, void* userData)
{
// Install the supplied function pointer and user data to
// be called during notification.
mNotificationRoutine = notificationRoutine;
mUserData = userData;
}
void AGATrackingIndicator::SetAttributes(Boolean isHorizontal, Boolean liveTracking, Boolean isProportional)
{
// Set options as specified.
mIsHorizontal = isHorizontal;
mLiveTracking = liveTracking;
mIsProportional = isProportional;
}
void AGATrackingIndicator::SetLiveTracking(Boolean liveTracking)
{
// Turn live tracking on or off.
mLiveTracking = liveTracking;
}
void AGATrackingIndicator::DrawObject()
{
// Call component drawing functions. These are all overridden
// by subclasses.
this->DrawBackground();
this->DrawIndicatorTrack();
this->DrawTrackEnds();
this->DrawIndicator();
}
Boolean AGATrackingIndicator::TrackMouse(Point mouseLocation)
{
if (! mEnabled)
return false;
// Track the mouse and return true if the indicator
// value was changed.
return this->TrackPart(mouseLocation, this->TrackTestPart(mouseLocation));
}
Boolean AGATrackingIndicator::TrackPart(Point mouseLocation, SInt32 partHit)
{
// Track the mouse in the specified part and return true
// if the indicator value was changed.
if (partHit != kIndicatorPress)
return false;
SInt32 originalValue = mValue;
Point oldPoint = mouseLocation;
Point newPoint = mouseLocation;
SInt32 oldValue = originalValue;
SInt32 newValue = originalValue;
Boolean isButtonDown = true; // ensure at least one time through
mGhostValue = mValue;
mIsPressed = true;
this->DrawIndicator(); // will draw it pressed
while (isButtonDown)
{
::GetMouse(&newPoint); // gives local coordinates
if (this->IsValidIndicatorTrackMouse(newPoint) &&
! ::EqualPt(newPoint, oldPoint))
{
newValue = this->GetValueFromMouseDelta(oldValue, mouseLocation, newPoint);
if (mLiveTracking)
{
SInt32 oldValue = mValue;
this->SetValue(newValue, kRedraw);
if (mValue != oldValue)
this->NotifyValue();
}
else
this->SetGhostValue(newValue, kRedraw);
oldPoint = newPoint;
}
isButtonDown = ::StillDown();
}
mIsPressed = false;
if (mLiveTracking)
this->DrawIndicator(); // unpressed
else
{
this->RemoveGhost(newValue);
this->DrawIndicator(); // unpressed
if (newValue != mValue) // don't notify if no change
{
this->SetValue(newValue, kRedraw); // will draw new indicator
this->NotifyValue();
}
}
return (mValue != originalValue);
}
SInt32 AGATrackingIndicator::GetValue()
{
// Return the current indicator value.
return mValue;
}
void AGATrackingIndicator::SetGhostValue(SInt32 newValue, Boolean redraw)
{
// Set the ghost indicator value, and optionally redraw it
// at its new position.
if (newValue > mMaximum)
newValue = mMaximum;
else if (newValue < mMinimum)
newValue = mMinimum;
if (newValue != mGhostValue)
{
if (redraw)
this->RemoveGhost(newValue);
mGhostValue = newValue;
if (redraw)
this->DrawGhost();
}
}
void AGATrackingIndicator::SetValue(SInt32 newValue, Boolean redraw)
{
// Set the indicator value, and optionally redraw it
// at its new position.
if (newValue > mMaximum)
newValue = mMaximum;
else if (newValue < mMinimum)
newValue = mMinimum;
if (newValue != mValue)
{
if (redraw)
this->RemoveIndicator(newValue);
mValue = newValue;
if (redraw)
this->DrawIndicator();
}
}
void AGATrackingIndicator::GetRange(SInt32* minimum, SInt32* maximum)
{
// Return the current min/max range.
*minimum = mMinimum;
*maximum = mMaximum;
}
void AGATrackingIndicator::SetRange(SInt32 newMinimum, SInt32 newMaximum, Boolean redraw)
{
// Set the min/max range, and optionally redraw.
if ((newMinimum != mMinimum) ||
(newMaximum != mMaximum))
{
if (redraw)
this->RemoveIndicator(mValue);
mMinimum = newMinimum;
mMaximum = newMaximum;
mValue = MaxSInt32(mMinimum, MinSInt32(mValue, mMaximum));
if (redraw)
this->DrawIndicator();
}
}
SInt32 AGATrackingIndicator::GetPageSize()
{
// Return the current indicator page size.
return mPageSize;
}
void AGATrackingIndicator::SetPageSize(SInt32 newPageSize, Boolean redraw)
{
// Set the indicator page size. Redraw is not
// necessary if the indicator is not proportional.
if (newPageSize != mPageSize)
{
if (redraw && mIsProportional)
this->RemoveIndicator(mValue);
mPageSize = newPageSize;
if (redraw && mIsProportional)
this->DrawIndicator();
}
}
SInt32 AGATrackingIndicator::TrackTestPart(Point /*mouseLocation*/)
{
// Must be overridden. Return the part value that the
// specified mouse position would hit.
return kNoTrackPress;
}
Boolean AGATrackingIndicator::IsValidIndicatorTrackMouse(Point mouseLocation)
{
// Usually overridden. Return true if the specified mouse
// position should be considered "in" for tracking purposes
// after the initial hit has succeeded. Return false if the
// specified mouse position is too far away from the control
// to use it for the next momentary tracking position.
return ::PtInRect(mouseLocation, &mBounds);
}
SInt32 AGATrackingIndicator::GetValueFromMouseDelta(SInt32 originalValue, Point /*originalMouseLocation*/, Point /*newMouseLocation*/)
{
// Must be overridden. Return the indicator value that should be
// applied assuming the supplied starting value and mouse hit point,
// and the supplied current mouse tracking location.
return originalValue;
}
void AGATrackingIndicator::DrawBackground()
{
// Override to paint the background area so that the
// indicator drawn at its old position will be wiped out.
// Clipping will be already set up to avoid excess flicker.
}
void AGATrackingIndicator::DrawIndicatorTrack()
{
// Override to draw the empty indicator track. Must include
// all possible indicator coverage.
}
void AGATrackingIndicator::DrawTrackEnds()
{
// Override to draw the track ends outside the possible
// indicator coverage if not drawn in DrawIndicatorTrack.
}
void AGATrackingIndicator::DrawIndicator()
{
// Override to draw the indicator at its current value/state.
}
void AGATrackingIndicator::RemoveIndicator(SInt32 /*newValue*/)
{
// Override to draw/erase whatever is needed to remove the
// current indicator in preparation for being drawn at
// the specified new value. The new value is supplied so
// that erasing can be kept to a minimal area.
}
void AGATrackingIndicator::DrawGhost()
{
// Override to draw the indicator in ghost mode at
// the current ghost value.
}
void AGATrackingIndicator::RemoveGhost(SInt32 /*newValue*/)
{
// Override to draw/erase whatever is needed to remove the
// ghost indicator in preparation for being drawn at
// the specified new value. The new value is supplied so
// that erasing can be kept to a minimal area.
}
void AGATrackingIndicator::NotifyValue()
{
// Call the installed notification routine, if any, with
// the installed user data and our new value.
if (mNotificationRoutine != NULL)
(*(mNotificationRoutine))(this, mValue, mUserData);
}
//
// AGAScrollBar ---------------------------------------------------------------
//
// This class implements a standard AGA scroll bar, with the additional
// ability to perform live tracking and a proportional thumb.
//
// These regions are used momentarily while tracking the scroll
// bar indicator to clip and optimize redrawing.
RgnHandle AGAScrollBar::mgSavedIndicatorClip = ::NewRgn();
RgnHandle AGAScrollBar::mgOldIndicatorClip = ::NewRgn();
RgnHandle AGAScrollBar::mgNewIndicatorClip = ::NewRgn();
AGAScrollBar::AGAScrollBar(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue)
: AGATrackingIndicator(bounds, minimum, maximum, initialValue)
{
// Construct with default options.
mLiveTracking = TestGrayCouncilDefault(kAGALiveScrolling);
mIsProportional = TestGrayCouncilDefault(kAGAProportionalScrolling);
mSingleStepSize = 1;
mPageStepSize = 1;
mActive = true;
}
AGAScrollBar::AGAScrollBar(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, SInt32 singleStepSize, SInt32 pageStepSize, SInt32 pageSize, Boolean liveTracking, Boolean proportional)
: AGATrackingIndicator(bounds, minimum, maximum, initialValue, pageSize, liveTracking, proportional)
{
// Construct with specified options.
mSingleStepSize = singleStepSize;
mPageStepSize = pageStepSize;
mActive = true;
}
AGAScrollBar::~AGAScrollBar()
{
}
void AGAScrollBar::SetRange(SInt32 newMinimum, SInt32 newMaximum, Boolean redraw)
{
// For scroll bars, min==max means the scroll bar is drawn disabled.
// So we need to catch a range change that changes this implicit state
// that is peculiar to this subclass. When this happens, we don't want
// the normal indicator redraw to happen; rather, we want to redraw the
// whole object in its new state.
Boolean wasEnabled = (mMaximum > mMinimum);
Boolean isEnabled = (newMaximum > newMinimum);
Boolean changedState = (isEnabled != wasEnabled);
AGATrackingIndicator::SetRange(newMinimum, newMaximum, redraw && ! changedState);
if (redraw && changedState)
this->DrawObject();
}
void AGAScrollBar::SetStepSizes(SInt32 singleStepSize, SInt32 pageStepSize)
{
// Set the scrolling step delta amounts.
mSingleStepSize = singleStepSize;
mPageStepSize = pageStepSize;
}
void AGAScrollBar::Activate(Boolean activateState, Boolean redraw)
{
// Set the active/inactive state. Scroll bars are the
// only control that have a different appearance when
// in an inactive window.
mActive = activateState;
if (redraw)
this->DrawObject();
}
Boolean AGAScrollBar::TrackPart(Point mouseLocation, SInt32 partHit)
{
// Track the mouse and return true if tracking changed the
// indicator value. Thumb tracking is handled by superclass.
// Scroll bar just handles arrow and page tracking.
if ((partHit != kArrowMinusPress) && (partHit != kArrowPlusPress) &&
(partHit != kPageMinusPress) && (partHit != kPagePlusPress))
return AGATrackingIndicator::TrackPart(mouseLocation, partHit);
if (mMaximum <= mMinimum) // implicitly disabled (no range)
return false;
Boolean wasIn = false;
Boolean isIn = true;
Boolean isButtonDown = true; // ensure at least one time through
Point newMouseLocation;
UInt32 accelerationDelay = 18; // will divide by 2 each time
while (isButtonDown)
{
if (isIn)
this->TrackDelta(partHit);
::GetMouse(&newMouseLocation); // gives local coordinates
isIn = (this->TrackTestPart(newMouseLocation) == partHit);
if (isIn != wasIn)
this->DrawArrow(partHit, isIn);
wasIn = isIn;
if (isButtonDown && (accelerationDelay != 0))
{
DelayFutureWhileStillDown(accelerationDelay);
accelerationDelay = accelerationDelay >> 1; // divide by 2
}
isButtonDown = ::StillDown();
}
if (isIn) // if finished IN, restore normal appearance
this->DrawArrow(partHit, kNotPressed);
return true;
}
SInt32 AGAScrollBar::TrackTestPart(Point mouseLocation)
{
// Return the part value that the specified mouse
// position would hit.
Rect arrowMinusRect = mBounds;
Rect arrowPlusRect = mBounds;
Rect pageMinusRect = mBounds;
Rect pagePlusRect = mBounds;
Rect indicatorRect;
this->GetIndicatorBox(mValue, &indicatorRect);
if (mIsHorizontal)
{
arrowPlusRect.left = arrowPlusRect.right - kArrowSize;
arrowMinusRect.right = arrowMinusRect.left + kArrowSize;
pageMinusRect.left = arrowMinusRect.right;
pageMinusRect.right = indicatorRect.left;
pagePlusRect.left = indicatorRect.right;
pagePlusRect.right = arrowPlusRect.left;
}
else
{
arrowPlusRect.top = arrowPlusRect.bottom - kArrowSize;
arrowMinusRect.bottom = arrowMinusRect.top + kArrowSize;
pageMinusRect.top = arrowMinusRect.bottom;
pageMinusRect.bottom = indicatorRect.top;
pagePlusRect.top = indicatorRect.bottom;
pagePlusRect.bottom = arrowPlusRect.top;
}
if (::PtInRect(mouseLocation, &arrowMinusRect))
return kArrowMinusPress;
else if (::PtInRect(mouseLocation, &arrowPlusRect))
return kArrowPlusPress;
else if (::PtInRect(mouseLocation, &pageMinusRect))
return kPageMinusPress;
else if (::PtInRect(mouseLocation, &pagePlusRect))
return kPagePlusPress;
else if (::PtInRect(mouseLocation, &indicatorRect))
return kIndicatorPress;
else
return kNoTrackPress;
}
Boolean AGAScrollBar::IsValidIndicatorTrackMouse(Point mouseLocation)
{
// Return true if the mouse is reasonably near
// the track.
Rect okRect = mBounds;
::InsetRect(&okRect, -32, -32); // slop for mouse tracking
return ::PtInRect(mouseLocation, &okRect);
}
SInt32 AGAScrollBar::GetValueFromMouseDelta(SInt32 originalValue, Point originalMouseLocation, Point newMouseLocation)
{
// Return the new indicator value based on the mouse delta
// from the original mouse location and indicator value.
SInt32 dontCare;
SInt32 valueRange = mMaximum - mMinimum;
SInt32 pixelRange = this->GetIndicatorPixelRange(&dontCare);
SInt32 pixelDelta;
float pixelFraction;
if (mIsHorizontal)
pixelDelta = newMouseLocation.h - originalMouseLocation.h;
else
pixelDelta = newMouseLocation.v - originalMouseLocation.v;
pixelFraction = ((float) pixelDelta) / (float) pixelRange;
float delta = pixelFraction * ((float) valueRange);
delta += (float) 0.5; // round to nearest integer, don't just truncate fraction
return originalValue + delta;
}
void AGAScrollBar::DrawIndicatorTrack()
{
AGADrawingEnvironment env;
// Draw the empty scroll bar track.
GDIterator iter;
Boolean deep;
Boolean enabled = mEnabled && (mMaximum > mMinimum);
while (iter.More(deep))
{
if (deep)
{
Rect r = mBounds;
if (mActive)
::RGBForeColor(&gAGARamp[rB]);
else
::RGBForeColor(&gAGARamp[r10]);
::FrameRect(&r);
if (mIsHorizontal)
::InsetRect(&r, kArrowSize - 1, 0);
else
::InsetRect(&r, 0, kArrowSize - 1);
if ((! mActive) || (! enabled))
{
::RGBForeColor(&gAGARamp[r1]);
::InsetRect(&r, 1, 1);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
if (mActive)
::RGBForeColor(&gAGARamp[r8]);
if (mIsHorizontal)
{
::MoveTo(r.left, r.top + 1);
::LineTo(r.left, r.bottom - 2);
::MoveTo(r.right - 1, r.top + 1);
::LineTo(r.right - 1, r.bottom - 2);
}
else
{
::MoveTo(r.left + 1, r.top);
::LineTo(r.right - 2, r.top);
::MoveTo(r.left + 1, r.bottom - 1);
::LineTo(r.right - 2, r.bottom - 1);
}
}
else // enabled
{
::RGBForeColor(&gAGARamp[r5]);
::InsetRect(&r, 1, 1);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
::RGBForeColor(&gAGARamp[rB]);
if (mIsHorizontal)
{
::MoveTo(r.left, r.top + 1);
::LineTo(r.left, r.bottom - 2);
::MoveTo(r.right - 1, r.top + 1);
::LineTo(r.right - 1, r.bottom - 2);
// Draw the shadowing.
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 2, r.top + 1);
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.left + 2, r.bottom - 4);
::LineTo(r.left + 2, r.top + 2);
::LineTo(r.right - 3, r.top + 2);
::RGBForeColor(&gAGARamp[r3]);
::MoveTo(r.left + 2, r.bottom - 2);
::LineTo(r.right - 2, r.bottom - 2);
::RGBForeColor(&gAGARamp[r4]);
::MoveTo(r.left + 3, r.bottom - 3);
::LineTo(r.right - 2, r.bottom - 3);
}
else
{
::MoveTo(r.left + 1, r.top);
::LineTo(r.right - 2, r.top);
::MoveTo(r.left + 1, r.bottom - 1);
::LineTo(r.right - 2, r.bottom - 1);
// Draw the shadowing.
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left + 1, r.bottom - 2);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 3, r.top + 1);
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.left + 2, r.bottom - 2);
::LineTo(r.left + 2, r.top + 2);
::LineTo(r.right - 4, r.top + 2);
::RGBForeColor(&gAGARamp[r3]);
::MoveTo(r.right - 2, r.top + 2);
::LineTo(r.right - 2, r.bottom - 2);
::RGBForeColor(&gAGARamp[r4]);
::MoveTo(r.right - 3, r.top + 3);
::LineTo(r.right - 3, r.bottom - 2);
}
}
}
else // 1-bit
{
Rect r = mBounds;
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&mBounds);
if (enabled && mActive)
{
if (mIsHorizontal)
{
::InsetRect(&r, kArrowSize - 1, 0);
::MoveTo(r.left, r.top + 1);
::LineTo(r.left, r.bottom - 2);
::MoveTo(r.right - 1, r.top + 1);
::LineTo(r.right - 1, r.bottom - 2);
}
else
{
::InsetRect(&r, 0, kArrowSize - 1);
::MoveTo(r.left + 1, r.top);
::LineTo(r.right - 2, r.top);
::MoveTo(r.left + 1, r.bottom - 1);
::LineTo(r.right - 2, r.bottom - 1);
}
}
}
}
}
void AGAScrollBar::DrawTrackEnds()
{
AGADrawingEnvironment env;
// Draw the scroll arrows.
this->DrawArrow(kArrowMinusPress, kNotPressed);
this->DrawArrow(kArrowPlusPress, kNotPressed);
}
void AGAScrollBar::DrawIndicator()
{
Boolean enabled = mEnabled && (mMaximum > mMinimum);
if ((! enabled) || (! mActive))
return;
AGADrawingEnvironment env;
// Draw the thumb indicator.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
enum { Fill, Light, TL, BR, Dark, kIndicatorColors };
UInt8 colorIndexes[kIndicatorColors];
Rect r = mBounds;
SInt32 startPt;
SInt32 valuePt;
SInt32 stopPt;
Point drawDirection;
Point moveDirection;
SInt16 lineLength;
if (deep)
{
if (mIsPressed)
{
colorIndexes[Fill] = r8;
colorIndexes[Light] = r3;
colorIndexes[TL] = r5;
colorIndexes[BR] = r10;
colorIndexes[Dark] = r12;
}
else
{
colorIndexes[Fill] = r5;
colorIndexes[Light] = r1;
colorIndexes[TL] = r3;
colorIndexes[BR] = r8;
colorIndexes[Dark] = r10;
}
}
else
{
if (mIsPressed)
{
colorIndexes[Fill] = rB;
colorIndexes[Light] = rB;
colorIndexes[TL] = rW;
colorIndexes[BR] = rB;
colorIndexes[Dark] = rB;
}
else
{
colorIndexes[Fill] = rW;
colorIndexes[Light] = rW;
colorIndexes[TL] = rB;
colorIndexes[BR] = rW;
colorIndexes[Dark] = rW;
}
}
this->GetIndicatorSpan(mValue, &startPt, &valuePt, &stopPt);
this->GetIndicatorBox(mValue, &r);
if (mIsHorizontal)
{
::SetPt(&drawDirection, 0, 1);
::SetPt(&moveDirection, 1, 0);
lineLength = r.bottom - r.top - 11;
}
else
{
::SetPt(&drawDirection, 1, 0);
::SetPt(&moveDirection, 0, 1);
lineLength = r.right - r.left - 11;
}
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::InsetRect(&r, 1, 1);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
if (deep)
{
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 2);
::Move(1, -1);
::LineTo(r.right - 3, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::MoveTo(r.right - 2, r.top + 2);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 2, r.bottom - 2);
::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
::MoveTo(r.left + 1, r.top + 1);
::Line(0, 0);
}
::MoveTo(r.left + 4 + (moveDirection.h * (((r.right - r.left) / 2) - 8)),
r.top + 4 + (moveDirection.v * (((r.bottom - r.top) / 2) - 8)));
if (! deep)
::Move(moveDirection.h, moveDirection.v);
for (SInt32 i = 0; i < 4; i++)
{
::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
::Line(0, 0);
::Move(drawDirection.h, drawDirection.v);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::Line(drawDirection.h * lineLength, drawDirection.v * lineLength);
::Move(moveDirection.h, moveDirection.v);
::Move(drawDirection.h, drawDirection.v);
::RGBForeColor(&gAGARamp[colorIndexes[Dark]]);
::Line(- (drawDirection.h * (lineLength+1)), - (drawDirection.v * (lineLength+1)));
::Move(moveDirection.h, moveDirection.v);
::Move(- drawDirection.h, - drawDirection.v);
}
}
}
void AGAScrollBar::RemoveIndicator(SInt32 newValue)
{
AGADrawingEnvironment env;
// Draw the track/background to remove the current
// indicator.
//
// Set clipping so we only draw the track to
// wipe out the old indicator, but not where
// the new indicator will get drawn anyway.
// This reduces flicker.
//
::GetClip(mgSavedIndicatorClip);
if (newValue != mValue)
{
Rect oldIndicatorBox;
Rect newIndicatorBox;
this->GetIndicatorBox(mValue, &oldIndicatorBox);
this->GetIndicatorBox(newValue, &newIndicatorBox);
::RectRgn(mgOldIndicatorClip, &oldIndicatorBox);
::RectRgn(mgNewIndicatorClip, &newIndicatorBox);
::DiffRgn(mgOldIndicatorClip, mgNewIndicatorClip, mgOldIndicatorClip);
::SetClip(mgOldIndicatorClip);
}
this->DrawIndicatorTrack();
::SetClip(mgSavedIndicatorClip);
}
void AGAScrollBar::DrawGhost()
{
AGADrawingEnvironment env;
// Draw the indicator as a ghost at the current mGhostValue
// position.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = mBounds;
SInt32 startPt;
SInt32 valuePt;
SInt32 stopPt;
Point drawDirection;
Point moveDirection;
SInt16 lineLength;
this->GetIndicatorSpan(mGhostValue, &startPt, &valuePt, &stopPt);
this->GetIndicatorBox(mGhostValue, &r);
if (deep)
{
if (mIsHorizontal)
{
::SetPt(&drawDirection, 0, 1);
::SetPt(&moveDirection, 1, 0);
lineLength = r.bottom - r.top - 11;
::RGBForeColor(&gAGARamp[r4]);
::InsetRect(&r, 1, 3);
::PaintRect(&r);
::InsetRect(&r, -1, -3);
::RGBForeColor(&gAGARamp[r11]);
::MoveTo(r.left, r.top + 1);
::Line(0, 0);
::MoveTo(r.right - 1, r.top + 1);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.left, r.top + 2);
::Line(0, 0);
::MoveTo(r.right - 1, r.top + 2);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left, r.top + 3);
::LineTo(r.left, r.bottom - 4);
::MoveTo(r.right - 1, r.top + 3);
::LineTo(r.right - 1, r.bottom - 4);
::RGBForeColor(&gAGARamp[r6]);
::MoveTo(r.left, r.bottom - 3);
::Line(0, 0);
::MoveTo(r.right - 1, r.bottom - 3);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r4]);
::MoveTo(r.left, r.bottom - 2);
::Line(0, 0);
::MoveTo(r.right - 1, r.bottom - 2);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r6]);
::MoveTo(r.left + 1, r.top + 1);
::LineTo(r.right - 2, r.top + 1);
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(r.left + 1, r.top + 2);
::LineTo(r.right - 2, r.top + 2);
::RGBForeColor(&gAGARamp[r3]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.right - 2, r.bottom - 3);
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.left + 1, r.bottom - 2);
::LineTo(r.right - 2, r.bottom - 2);
}
else
{
::SetPt(&drawDirection, 1, 0);
::SetPt(&moveDirection, 0, 1);
lineLength = r.right - r.left - 11;
::RGBForeColor(&gAGARamp[r4]);
::InsetRect(&r, 3, 1);
::PaintRect(&r);
::InsetRect(&r, -3, -1);
::RGBForeColor(&gAGARamp[r11]);
::MoveTo(r.left + 1, r.top);
::Line(0, 0);
::MoveTo(r.left + 1, r.bottom - 1);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.left + 2, r.top);
::Line(0, 0);
::MoveTo(r.left + 2, r.bottom - 1);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left + 3, r.top);
::LineTo(r.right - 4, r.top);
::MoveTo(r.left + 3, r.bottom - 1);
::LineTo(r.right - 4, r.bottom - 1);
::RGBForeColor(&gAGARamp[r6]);
::MoveTo(r.right - 3, r.top);
::Line(0, 0);
::MoveTo(r.right - 3, r.bottom - 1);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r4]);
::MoveTo(r.right - 2, r.top);
::Line(0, 0);
::MoveTo(r.right - 2, r.bottom - 1);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r6]);
::MoveTo(r.left + 1, r.top + 1);
::LineTo(r.left + 1, r.bottom - 2);
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(r.left + 2, r.top + 1);
::LineTo(r.left + 2, r.bottom - 2);
::RGBForeColor(&gAGARamp[r3]);
::MoveTo(r.right - 3, r.top + 1);
::LineTo(r.right - 3, r.bottom - 2);
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.right - 2, r.top + 1);
::LineTo(r.right - 2, r.bottom - 2);
}
::MoveTo(r.left + 4 + (moveDirection.h * (((r.right - r.left) / 2) - 8)),
r.top + 4 + (moveDirection.v * (((r.bottom - r.top) / 2) - 8)));
for (SInt32 i = 0; i < 4; i++)
{
::RGBForeColor(&gAGARamp[r2]);
::Line(drawDirection.h * (lineLength+1), drawDirection.v * (lineLength+1));
::Move(moveDirection.h, moveDirection.v);
::Move(drawDirection.h, drawDirection.v);
::RGBForeColor(&gAGARamp[r6]);
::Line(- (drawDirection.h * (lineLength+1)), - (drawDirection.v * (lineLength+1)));
::Move(moveDirection.h, moveDirection.v);
::Move(- drawDirection.h, - drawDirection.v);
}
}
else
{
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
}
}
}
void AGAScrollBar::RemoveGhost(SInt32 /*newValue*/)
{
AGADrawingEnvironment env;
// Draw the track/background to remove the current
// ghost indicator.
Rect r;
RgnHandle savedClip = ::NewRgn();
::GetClip(savedClip);
this->GetIndicatorBox(mGhostValue, &r);
::ClipRect(&r);
this->DrawIndicatorTrack();
this->DrawIndicator();
::SetClip(savedClip);
}
void AGAScrollBar::TrackDelta(SInt32 partHit)
{
// Change our value based on the delta amount
// for the part that was hit. Do notification
// of the value change.
SInt32 oldValue = mValue;
SInt32 newValue = mValue;
switch (partHit)
{
case kPageMinusPress:
newValue -= mPageStepSize;
break;
case kArrowMinusPress:
newValue -= mSingleStepSize;
break;
case kArrowPlusPress:
newValue += mSingleStepSize;
break;
case kPagePlusPress:
newValue += mPageStepSize;
break;
}
this->SetValue(newValue, kRedraw);
if (mValue != oldValue)
this->NotifyValue();
}
void AGAScrollBar::DrawArrow(SInt32 arrowPart, Boolean pressed)
{
AGADrawingEnvironment env;
// Draw the specified arrow in the specified mode.
if ((arrowPart != kArrowMinusPress) &&
(arrowPart != kArrowPlusPress))
return;
enum { Fill, TL, BR, Arrow, kNumArrowColors };
Boolean enabled = mEnabled && (mMaximum > mMinimum);
UInt8 colorIndexes[kNumArrowColors];
Rect r = mBounds;
if (mIsHorizontal)
{
if (arrowPart == kArrowPlusPress)
r.left = r.right - kArrowSize;
else
r.right = r.left + kArrowSize;
}
else
{
if (arrowPart == kArrowPlusPress)
r.top = r.bottom - kArrowSize;
else
r.bottom = r.top + kArrowSize;
}
// Note: we don't draw the outer frame.
// That's already been drawn.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
if (! mActive)
{
colorIndexes[Fill] = r1;
colorIndexes[TL] = r1;
colorIndexes[BR] = r1;
colorIndexes[Arrow] = r1;
}
else if (pressed)
{
colorIndexes[Fill] = r8;
colorIndexes[TL] = r10;
colorIndexes[BR] = r6;
colorIndexes[Arrow] = rB;
}
else if (enabled)
{
colorIndexes[Fill] = r2;
colorIndexes[TL] = rW;
colorIndexes[BR] = r5;
colorIndexes[Arrow] = rB;
}
else // disabled
{
colorIndexes[Fill] = r2;
colorIndexes[TL] = rW;
colorIndexes[BR] = r4;
colorIndexes[Arrow] = r8;
}
}
else
{
if ((! mActive) || ! enabled)
{
colorIndexes[Fill] = rW;
colorIndexes[TL] = rW;
colorIndexes[BR] = rW;
colorIndexes[Arrow] = rW;
}
else if (pressed)
{
colorIndexes[Fill] = rB;
colorIndexes[TL] = rB;
colorIndexes[BR] = rB;
colorIndexes[Arrow] = rW;
}
else // unpressed + enabled
{
colorIndexes[Fill] = rW;
colorIndexes[TL] = rW;
colorIndexes[BR] = rW;
colorIndexes[Arrow] = rB;
}
}
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::InsetRect(&r, 1, 1);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 3, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::MoveTo(r.right - 2, r.top + 2);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 2, r.bottom - 2);
::RGBForeColor(&gAGARamp[colorIndexes[Arrow]]);
SInt16 direction = (arrowPart == kArrowPlusPress) ? 1 : -1;
SInt16 offset = (arrowPart == kArrowPlusPress) ? 6 : 9;
if (mIsHorizontal)
{
::MoveTo(r.left + offset, ((r.top + r.bottom) / 2) - 4);
::Line(0, 7);
::Move(direction, -6);
::Line(0, 5);
::Move(direction, -4);
::Line(0, 3);
::Move(direction, -2);
::Line(0, 1);
}
else
{
::MoveTo(((r.left + r.right) / 2) - 4, r.top + offset);
::Line(7, 0);
::Move(-6, direction);
::Line(5, 0);
::Move(-4, direction);
::Line(3, 0);
::Move(-2, direction);
::Line(1, 0);
}
}
}
void AGAScrollBar::GetIndicatorBox(SInt32 indicatorValue, Rect* indicatorBox)
{
// Return the bounds of the indicator box assuming that
// it has specified indicator value.
Rect r = mBounds;
SInt32 startPt;
SInt32 valuePt;
SInt32 stopPt;
this->GetIndicatorSpan(indicatorValue, &startPt, &valuePt, &stopPt);
if (mIsHorizontal)
{
r.left = startPt;
r.right = stopPt;
}
else
{
r.top = startPt;
r.bottom = stopPt;
}
*indicatorBox = r;
}
SInt32 AGAScrollBar::GetIndicatorPixelRange(SInt32* proportionalIndicatorPixels)
{
// Return the pixel range that the center point of the indicator
// can travel along the track, and also return the amount of
// range reduction that is caused by proportional indicator growth.
// Non-proportional indicators use the full track range, minus
// the size of the indicator itself.
SInt32 range;
*proportionalIndicatorPixels = 0;
if (mIsHorizontal)
range = mBounds.right - mBounds.left - (2 * (kArrowSize + kIndicatorPixelInset)) + 1;
else
range = mBounds.bottom - mBounds.top - (2 * (kArrowSize + kIndicatorPixelInset)) + 1;
if (mIsProportional)
{
SInt32 pagePixels;
pagePixels =
(range * (((float) mPageSize) / ((float) (mMaximum - mMinimum))));
if (pagePixels > 0)
{
range -= pagePixels;
*proportionalIndicatorPixels = pagePixels;
}
}
return range;
}
void AGAScrollBar::GetIndicatorPixelEnds(SInt32* startPt, SInt32* stopPt)
{
// Return the start and end pixel locations of the indicator
// track traveled by the center point of the indicator.
SInt32 dontCare;
SInt32 range = this->GetIndicatorPixelRange(&dontCare);
if (mIsHorizontal)
{
*startPt = ((mBounds.left + mBounds.right) / 2) - (range / 2) - 1;
// Bump by 1 if width is odd but range isn't.
if ((((mBounds.right - mBounds.left) & 1) != 0) &&
((range & 1) == 0))
(*startPt)++;
}
else
{
*startPt = ((mBounds.top + mBounds.bottom) / 2) - (range / 2) - 1;
// Bump by 1 if height is odd but range isn't.
if ((((mBounds.bottom - mBounds.top) & 1) != 0) &&
((range & 1) == 0))
(*startPt)++;
}
*stopPt = *startPt + range; // avoid rounding of 1/2 pixel twice
}
void AGAScrollBar::GetIndicatorSpan(SInt32 value, SInt32* startPt, SInt32* valuePt, SInt32* stopPt)
{
// Return the pixel locations of the indicator's ends and value.
SInt32 proportionalIndicatorPixels;
SInt32 trackStart;
SInt32 trackStop;
SInt32 trackRange = this->GetIndicatorPixelRange(&proportionalIndicatorPixels);
this->GetIndicatorPixelEnds(&trackStart, &trackStop);
*valuePt = trackStart +
(trackRange * (((float) (value - mMinimum)) / ((float) (mMaximum - mMinimum))));
*startPt = *valuePt - kIndicatorPixelInset - (proportionalIndicatorPixels / 2);
*stopPt = *startPt + (2 * kIndicatorPixelInset) + proportionalIndicatorPixels + 1;
}
//
// AGASlider ---------------------------------------------------------------
//
// This class implements a standard AGA slider, with the additional
// ability to perform live tracking and a proportional thumb.
//
// These regions are used momentarily while tracking the slider
// indicator to clip and optimize redrawing.
RgnHandle AGASlider::mgSavedIndicatorClip = ::NewRgn();
RgnHandle AGASlider::mgOldIndicatorClip = ::NewRgn();
RgnHandle AGASlider::mgNewIndicatorClip = ::NewRgn();
AGASlider::AGASlider(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, const AGATextStyle& textStyle, SInt16 labelsID)
: AGATrackingIndicator(bounds, minimum, maximum, initialValue)
{
// Construct with default options.
mPageSize = 0;
mLabelStringHandles = NULL;
mJustification = teFlushDefault;
mTextStyle = textStyle;
if (labelsID == 0)
{
mSliderKind = kRectSlider;
mLiveTracking = TestGrayCouncilDefault(kAGALiveRSliders);
mIsProportional = TestGrayCouncilDefault(kAGAProportionalRSliders);
}
else
{
mSliderKind = kPointerSlider;
this->SetLabelsFromResource(labelsID);
mLiveTracking = TestGrayCouncilDefault(kAGALivePSliders);
mIsProportional = TestGrayCouncilDefault(kAGAProportionalPSliders);
}
}
AGASlider::AGASlider(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, const AGATextStyle& textStyle, SInt16 labelsID, SliderKind kind, Boolean liveTracking, Boolean proportional)
: AGATrackingIndicator(bounds, minimum, maximum, initialValue, 1, liveTracking, proportional)
{
// Construct with specified options.
mPageSize = 0;
mLabelStringHandles = NULL;
mJustification = teFlushDefault;
mSliderKind = kind;
mTextStyle = textStyle;
this->SetLabelsFromResource(labelsID);
}
AGASlider::~AGASlider()
{
// Destruct by releasing memory allocated for labels.
this->DisposeLabels();
}
void AGASlider::SetSliderKind(SliderKind kind)
{
// Set the slider kind (pointy or rectangular).
mSliderKind = kind;
}
void AGASlider::SetLabelsFromResource(SInt16 stringListResourceID)
{
// Build the slider labels from the specified 'STR#' resource.
// A label slot is allocated for each string in the resource;
// there will be a visual label tick for each of these strings.
// If the current min/max range is smaller than the number of
// labels (i.e., it's uninitialized), the min/max range will
// be set to match the number of labels.
this->DisposeLabels();
if (stringListResourceID != 0)
{
SInt16** stringListHandle = (SInt16**) ::GetResource('STR#', stringListResourceID);
SInt16 numLabels = (stringListHandle == NULL) ? 0 : **stringListHandle;
if (numLabels != 0)
{
mLabelStringHandles = ::NewHandleClear(numLabels * sizeof(StringHandle));
for (SInt16 i = 0; i < numLabels; i++)
{
Str255 aLabel;
StringHandle aStringHandle;
::GetIndString(aLabel, stringListResourceID, i+1);
aStringHandle = ::NewString(aLabel);
((StringHandle*)(*mLabelStringHandles))[i] = aStringHandle;
}
}
if ((mMaximum - mMinimum + 1) < numLabels)
mMaximum = mMinimum + numLabels - 1;
}
}
void AGASlider::SetNumLabels(UInt32 numLabels)
{
// Allocate slots for the specified number of labels.
// Any existing labels are thrown away.
this->DisposeLabels();
mLabelStringHandles = ::NewHandleClear(numLabels * sizeof(StringHandle));
if ((mMaximum - mMinimum + 1) < numLabels)
mMaximum = mMinimum + numLabels - 1;
}
void AGASlider::SetLabel(UInt32 labelIndex, StringPtr itsLabel)
{
// Assign the specified string to the specified label slot.
if (mLabelStringHandles != NULL)
{
UInt32 numLabels = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
if (labelIndex < numLabels)
((StringHandle*)(*mLabelStringHandles))[labelIndex] = ::NewString(itsLabel);
}
}
void AGASlider::GetLabel(UInt32 labelIndex, StringPtr itsLabel)
{
// Return the label string of the specified label slot.
itsLabel[0] = 0;
if (mLabelStringHandles != NULL)
{
UInt32 numLabels = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
if (labelIndex < numLabels)
{
Ptr sourceStringPtr = (Ptr) *(((StringHandle*)(*mLabelStringHandles))[labelIndex]);
::BlockMoveData(sourceStringPtr, itsLabel, 1 + *sourceStringPtr);
}
}
}
void AGASlider::SetLabelsStyle(const AGATextStyle& textStyle)
{
// Set the QuickDraw text style for the labels.
mTextStyle = textStyle;
}
void AGASlider::SetJustification(SInt32 justification)
{
// Set the justification of the slider. For vertical
// sliders, default/left means the slider is on the
// left and the labels are on the right; flush right
// reverses this. For horizontal sliders, default/left
// means the slider is above and the labels are below;
// flush right reverses this.
// In fact, for "teFlushDefault", the system script
// direction is checked at runtime, so this is usually
// what you should use. Use flush right or flush left
// to force it one way or another.
mJustification = justification;
}
SInt32 AGASlider::TrackTestPart(Point mouseLocation)
{
// Return the indicator part value if the mouse location
// would hit the indicator.
Rect indicatorRect;
this->GetIndicatorBox(mValue, &indicatorRect);
if (::PtInRect(mouseLocation, &indicatorRect))
return kIndicatorPress;
else
return kNoTrackPress;
}
Boolean AGASlider::IsValidIndicatorTrackMouse(Point mouseLocation)
{
// Return true if the mouse location is reasonably close
// to the indicator track. This will depend on the
// justification.
Rect okRect = mBounds;
if (mIsHorizontal)
{
if (RuntimeJustify(mJustification) == teFlushLeft)
okRect.bottom = okRect.top + kIndicatorWidth;
else
okRect.top = okRect.bottom - kIndicatorWidth;
}
else
{
if (RuntimeJustify(mJustification) == teFlushLeft)
okRect.right = okRect.left + kIndicatorWidth;
else
okRect.left = okRect.right - kIndicatorWidth;
}
::InsetRect(&okRect, -32, -32); // slop for mouse tracking
return ::PtInRect(mouseLocation, &okRect);
}
SInt32 AGASlider::GetValueFromMouseDelta(SInt32 originalValue, Point originalMouseLocation, Point newMouseLocation)
{
// Return the new potential indicator value based on the mouse
// delta from the original click location and the original value.
SInt32 dontCare;
SInt32 valueRange = mMaximum - mMinimum;
SInt32 pixelRange = this->GetIndicatorPixelRange(&dontCare);
SInt32 pixelDelta;
float pixelFraction;
if (mIsHorizontal)
pixelDelta = newMouseLocation.h - originalMouseLocation.h;
else
pixelDelta = newMouseLocation.v - originalMouseLocation.v;
pixelFraction = ((float) pixelDelta) / (float) pixelRange;
float delta = pixelFraction * ((float) valueRange);
delta += (float) 0.5; // round to nearest integer, don't just truncate fraction
return originalValue + delta;
}
void AGASlider::DrawBackground()
{
AGADrawingEnvironment env;
// Paint the background and labels.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
this->ApplyBackgroundColor();
else
::RGBForeColor(&gAGARamp[rW]);
}
::PaintRect(&mBounds);
iter.Cleanup(); // Restore clipping since not yet destructed.
this->DrawLabels();
}
void AGASlider::DrawIndicatorTrack()
{
AGADrawingEnvironment env;
// Draw the empty slider track.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
Rect trackFrame;
this->GetTrackFrame(&trackFrame, kIncludeBackground);
this->ApplyBackgroundColor();
::PaintRect(&trackFrame);
this->GetTrackFrame(&trackFrame, kTrackOnly);
if (mEnabled)
::RGBForeColor(&gAGARamp[rB]);
else
::RGBForeColor(&gAGARamp[r8]);
::InsetRect(&trackFrame, 1, 1);
::MoveTo(trackFrame.left + 1, trackFrame.top);
::LineTo(trackFrame.right - 2, trackFrame.top);
::Move(1, 1);
::LineTo(trackFrame.right - 1, trackFrame.bottom - 2);
::Move(-1, 1);
::LineTo(trackFrame.left + 1, trackFrame.bottom - 1);
::Move(-1, -1);
::LineTo(trackFrame.left, trackFrame.top + 1);
::InsetRect(&trackFrame, 1, 1);
if (mEnabled)
::RGBForeColor(&gAGARamp[r5]);
else
::RGBForeColor(&gAGARamp[r4]);
::PaintRect(&trackFrame);
if (mEnabled)
{
::InsetRect(&trackFrame, -2, -2);
::MoveTo(trackFrame.left, trackFrame.bottom - 3);
::LineTo(trackFrame.left, trackFrame.top + 1);
::Line(1, 0);
::Line(0, -1);
::LineTo(trackFrame.right - 3, trackFrame.top);
if (mIsHorizontal)
{
::Move(1, 1);
::Line(0, 0);
}
::RGBForeColor(&gAGARamp[rW]);
::MoveTo(trackFrame.left + 1, trackFrame.bottom - 2);
::Line(0, 0);
::Move(1, 1);
::LineTo(trackFrame.right - 2, trackFrame.bottom - 1);
::Line(0, -1);
::Line(1, 0);
::LineTo(trackFrame.right - 1, trackFrame.top + 2);
if (! mIsHorizontal)
{
::Move(-1, -1);
::Line(0, 0);
}
}
}
else // 1 -bit
{
Rect trackFrame;
this->GetTrackFrame(&trackFrame, kIncludeBackground);
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&trackFrame);
this->GetTrackFrame(&trackFrame, kTrackOnly);
::RGBForeColor(&gAGARamp[rB]);
if (! mEnabled)
::PenPat(&qd.gray);
::InsetRect(&trackFrame, 1, 1);
::MoveTo(trackFrame.left + 1, trackFrame.top);
::LineTo(trackFrame.right - 2, trackFrame.top);
::Move(1, 1);
::LineTo(trackFrame.right - 1, trackFrame.bottom - 2);
::Move(-1, 1);
::LineTo(trackFrame.left + 1, trackFrame.bottom - 1);
::Move(-1, -1);
::LineTo(trackFrame.left, trackFrame.top + 1);
if (! mEnabled)
::PenPat(&qd.black);
}
}
}
void AGASlider::DrawIndicator()
{
AGADrawingEnvironment env;
// Draw the slider indicator.
Rect indicatorRect;
this->GetIndicatorBox(mValue, &indicatorRect);
if (mSliderKind == kRectSlider)
this->DrawRectIndicator(&indicatorRect, kNormalIndicator);
else
this->DrawPointerIndicator(&indicatorRect, kNormalIndicator);
}
void AGASlider::DrawGhost()
{
AGADrawingEnvironment env;
// Draw the ghost slider indicator.
Rect indicatorRect;
this->GetIndicatorBox(mGhostValue, &indicatorRect);
if (mSliderKind == kRectSlider)
this->DrawRectIndicator(&indicatorRect, kGhostIndicator);
else
this->DrawPointerIndicator(&indicatorRect, kGhostIndicator);
}
void AGASlider::DrawLabels()
{
AGADrawingEnvironment env;
// Draw the slider labels and ticks.
UInt32 numHandles = 0;
if (mLabelStringHandles != NULL)
numHandles = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
if (numHandles < 2) // Gotta at least label the ends, man!
return;
SInt16 tickRange;
Point tickOrigin;
Point drawDirection;
Point moveDirection;
Rect trackFrame;
Boolean flushLeft = (RuntimeJustify(mJustification) == teFlushLeft);
FontInfo fontInfo;
mTextStyle.PrepareForDrawing();
::GetFontInfo(&fontInfo);
this->GetTrackFrame(&trackFrame, kTrackOnly);
if (mIsHorizontal)
{
tickRange = trackFrame.right - trackFrame.left - (2 * kLabelTickEndInset) - 1;
drawDirection.h = 0;
drawDirection.v = 1;
moveDirection.h = 1;
moveDirection.v = 0;
tickOrigin.h = trackFrame.left + kLabelTickEndInset;
if (flushLeft)
tickOrigin.v = trackFrame.bottom + kLabelTickOffset;
else
tickOrigin.v = trackFrame.top - kLabelTickOffset - 2 - kLabelTickLength;
}
else
{
tickRange = trackFrame.bottom - trackFrame.top - (2 * kLabelTickEndInset) - 1;
drawDirection.h = 1;
drawDirection.v = 0;
moveDirection.h = 0;
moveDirection.v = 1;
tickOrigin.v = trackFrame.top + kLabelTickEndInset;
if (flushLeft)
tickOrigin.h = trackFrame.right + kLabelTickOffset;
else
tickOrigin.h = trackFrame.left - kLabelTickOffset - 2 - kLabelTickLength;
}
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
for (UInt32 i = 0; i < numHandles; i++)
{
Point tickLocation;
float fraction = ((float) i) / ((float) (numHandles - 1));
tickLocation.h = tickOrigin.h + (moveDirection.h * tickRange * fraction);
tickLocation.v = tickOrigin.v + (moveDirection.v * tickRange * fraction);
::MoveTo(tickLocation.h, tickLocation.v);
::RGBForeColor(&gAGARamp[rB]);
if (! mEnabled)
{
if (deep)
::RGBForeColor(&gAGARamp[r7]);
else
::PenPat(&qd.gray);
}
::Line(drawDirection.h * (kLabelTickLength + 1), drawDirection.v * (kLabelTickLength + 1));
::PenNormal();
if (deep)
{
// If disabled, we still draw in order to erase the 7/W
// shading pixels from prior enabled drawing.
if (mEnabled)
::RGBForeColor(&gAGARamp[r7]);
else
this->ApplyBackgroundColor();
::Line(moveDirection.h, moveDirection.v);
::Line( - (kLabelTickLength * drawDirection.h), - (kLabelTickLength * drawDirection.v));
if (mEnabled)
::RGBForeColor(&gAGARamp[rW]);
::Move(-1, -1);
::Line(-moveDirection.h, -moveDirection.v);
::Line(drawDirection.h * kLabelTickLength, drawDirection.v * kLabelTickLength);
}
Str255 aLabel;
Rect labelBox;
SInt16 labelHeight = fontInfo.ascent + fontInfo.descent;
SInt16 labelWidth;
SInt32 textJustification;
this->GetLabel(i, aLabel);
labelWidth = ::StringWidth(aLabel);
if (mIsHorizontal)
{
textJustification = teCenter;
labelBox.left = tickLocation.h - (labelWidth / 2);
labelBox.right = labelBox.left + labelWidth;
if (flushLeft)
{
labelBox.top = tickLocation.v + 9;
labelBox.bottom = labelBox.top + labelHeight;
}
else
{
labelBox.bottom = tickLocation.v - 2;
labelBox.top = labelBox.bottom - labelHeight;
}
}
else
{
textJustification = mJustification;
labelBox.top = tickLocation.v - (labelHeight / 2);
labelBox.bottom = labelBox.top + labelHeight;
if (flushLeft)
{
labelBox.left = tickLocation.h + 11;
labelBox.right = labelBox.left + labelWidth;
}
else
{
labelBox.right = tickLocation.h - 2;
labelBox.left = labelBox.right - labelWidth;
}
}
//
// To make view layout simpler, we assume that the labels may
// extend outside the mBounds. So if this happens
// we need to make sure we aren't being clipped out, but also
// make sure we don't extend the unclipped area out to other
// screens during device iteration.
//
RgnHandle savedRegion = NULL;
if ((labelBox.left < mBounds.left) ||
(labelBox.right > mBounds.right))
{
savedRegion = ::NewRgn();
::GetClip(savedRegion);
::InsetRect(&labelBox, -1, -1);
::ClipRect(&labelBox);
::InsetRect(&labelBox, 1, 1);
iter.ClipFurtherToCurrentDevice();
}
AGAStringOut(aLabel, &labelBox, kNoTruncation, textJustification, mEnabled ? kNormalOutput : kDisabledOutput, deep, mTextStyle);
if (savedRegion != NULL)
{
::SetClip(savedRegion);
::DisposeRgn(savedRegion);
}
}
}
}
void AGASlider::DrawRectIndicator(Rect* indicatorRect, Boolean isGhost)
{
AGADrawingEnvironment env;
// Draw the rectangular slider indicator at the
// specified location. The location will be sized
// to account for a proportional indicator.
enum { Frame, Fill, Corner, Light, TL, BR, Dark, Grip, BG, kNumIndicatorColors };
UInt8 colorIndexes[kNumIndicatorColors];
Rect r = *indicatorRect;
Point drawDirection;
Point moveDirection;
SInt16 lineLength;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
colorIndexes[BG] = r2;
if (isGhost)
{
colorIndexes[Frame] = r7;
colorIndexes[Fill] = r2;
colorIndexes[Corner] = r1;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[BR] = r4;
colorIndexes[Dark] = r5;
colorIndexes[Grip] = rW;
}
else if (! mEnabled)
{
colorIndexes[Frame] = r8;
colorIndexes[Fill] = r2;
colorIndexes[Corner] = r2;
colorIndexes[Light] = r2;
colorIndexes[TL] = r2;
colorIndexes[BR] = r2;
// n/a colorIndexes[Dark] = r9;
colorIndexes[Grip] = r2;
}
else if (mIsPressed)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = r8;
colorIndexes[Corner] = r3;
colorIndexes[Light] = r3;
colorIndexes[TL] = r5;
colorIndexes[BR] = r10;
colorIndexes[Dark] = r12;
colorIndexes[Grip] = r5;
}
else // normal
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = r5;
colorIndexes[Corner] = r1;
colorIndexes[Light] = r1;
colorIndexes[TL] = r3;
colorIndexes[BR] = r8;
colorIndexes[Dark] = r10;
colorIndexes[Grip] = r3;
}
}
else // 1-bit
{
colorIndexes[BG] = rW;
if (isGhost)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rW;
colorIndexes[Corner] = rW;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[BR] = rW;
colorIndexes[Dark] = rW;
colorIndexes[Grip] = rB;
}
else if (! mEnabled)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rW;
colorIndexes[Corner] = rW;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[BR] = rW;
colorIndexes[Dark] = rW;
colorIndexes[Grip] = rW;
}
else if (mIsPressed)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rB;
colorIndexes[Corner] = rB;
colorIndexes[Light] = rB;
colorIndexes[TL] = rB;
colorIndexes[BR] = rB;
colorIndexes[Dark] = rB;
colorIndexes[Grip] = rW;
}
else // normal
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rW;
colorIndexes[Corner] = rW;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[BR] = rW;
colorIndexes[Dark] = rW;
colorIndexes[Grip] = rB;
}
}
::RGBForeColor(&gAGARamp[colorIndexes[Frame]]);
::FrameRect(&r);
::RGBForeColor(&gAGARamp[colorIndexes[BG]]);
::MoveTo(r.left, r.top);
::Line(0, 0);
::MoveTo(r.right - 1, r.top);
::Line(0, 0);
::MoveTo(r.right - 1, r.bottom - 1);
::Line(0, 0);
::MoveTo(r.left, r.bottom - 1);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::InsetRect(&r, 1, 1);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
::MoveTo(r.left + 1, r.top + 1);
::Line(0, 0);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 2);
::Move(1, -1);
::LineTo(r.right - 3, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::Move(1, 1);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 2, r.bottom - 2);
if (mIsHorizontal)
{
::SetPt(&drawDirection, 0, 1);
::SetPt(&moveDirection, 1, 0);
lineLength = r.bottom - r.top - 10;
}
else
{
::SetPt(&drawDirection, 1, 0);
::SetPt(&moveDirection, 0, 1);
lineLength = r.right - r.left - 10;
}
if (mEnabled)
{
::MoveTo(r.left + 3 + drawDirection.h + (moveDirection.h * (((r.right - r.left) / 2) - 6)),
r.top + 3 + drawDirection.v + (moveDirection.v * (((r.bottom - r.top) / 2) - 6)));
if (! deep)
::Move(moveDirection.h, moveDirection.v);
for (SInt32 i = 0; i < 3; i++)
{
::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
::Line(drawDirection.h, drawDirection.v);
::RGBForeColor(&gAGARamp[colorIndexes[Grip]]);
::Line(drawDirection.h * (lineLength-1), drawDirection.v * (lineLength-1));
::Move(moveDirection.h, moveDirection.v);
::Move(drawDirection.h, drawDirection.v);
::RGBForeColor(&gAGARamp[colorIndexes[Dark]]);
::Line(- (drawDirection.h * lineLength), - (drawDirection.v * lineLength));
::Move(moveDirection.h, moveDirection.v);
::Move(- drawDirection.h, - drawDirection.v);
}
}
if (isGhost && deep)
{
// Draw the little see-thru track slides.
// They run inverse draw direction from the grip lines.
// To handle proportional indicators, we need to vary
// the length of the track slides on the flat part.
SInt32 wholeFlatLength;
SInt32 firstFlatLength;
SInt32 remainingFlatLength;
if (mIsHorizontal)
wholeFlatLength = r.right - r.left - 10;
else
wholeFlatLength = r.bottom - r.top - 10;
firstFlatLength = wholeFlatLength / 2;
remainingFlatLength = wholeFlatLength - firstFlatLength; // don't round down twice
::RGBForeColor(&gAGARamp[r11]);
::MoveTo(r.left + (drawDirection.h * 5), r.top + (drawDirection.v * 5));
for (UInt32 i = 0; i < 2; i++)
{
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r5]);
::Line(moveDirection.h * firstFlatLength, moveDirection.v * firstFlatLength);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r9]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r9]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r9]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r5]);
::Line(moveDirection.h * remainingFlatLength, moveDirection.v * remainingFlatLength);
::RGBForeColor(&gAGARamp[r7]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r11]);
::Line(0, 0);
::MoveTo(r.left + (drawDirection.h * 9), r.top + (drawDirection.v * 9));
}
}
}
}
void AGASlider::DrawPointerIndicator(Rect* indicatorRect, Boolean isGhost)
{
AGADrawingEnvironment env;
// Draw the pointy slider indicator at the
// specified location. The location will be sized
// to account for a proportional indicator.
enum { Frame, Fill, Corner, Light, TL, Grip, BR, Dark, kNumIndicatorColors };
UInt8 colorIndexes[kNumIndicatorColors];
Rect r = *indicatorRect;
Point drawDirection;
Point moveDirection;
SInt16 lineLength;
SInt16 propExtra; // extra pixels due to proportional indicator shape
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
if (isGhost)
{
colorIndexes[Frame] = r7;
colorIndexes[Fill] = r2;
colorIndexes[Corner] = r1;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[Grip] = rW;
colorIndexes[BR] = r4;
colorIndexes[Dark] = r5;
}
else if (! mEnabled)
{
colorIndexes[Frame] = r8;
colorIndexes[Fill] = r2;
colorIndexes[Corner] = r2;
colorIndexes[Light] = r2;
colorIndexes[TL] = r2;
colorIndexes[Grip] = r2;
colorIndexes[BR] = r2;
// n/a colorIndexes[Dark] = r9;
}
else if (mIsPressed)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = r8;
colorIndexes[Corner] = r3;
colorIndexes[Light] = r3;
colorIndexes[TL] = r5;
colorIndexes[Grip] = r5;
colorIndexes[BR] = r10;
colorIndexes[Dark] = r12;
}
else // normal
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = r5;
colorIndexes[Corner] = r1;
colorIndexes[Light] = r1;
colorIndexes[TL] = r3;
colorIndexes[Grip] = r3;
colorIndexes[BR] = r8;
colorIndexes[Dark] = r10;
}
}
else // 1-bit
{
if (isGhost)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rW;
colorIndexes[Corner] = rW;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[Grip] = rW;
colorIndexes[BR] = rW;
colorIndexes[Dark] = rW;
}
else if (! mEnabled)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rW;
colorIndexes[Corner] = rW;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[Grip] = rW;
colorIndexes[BR] = rW;
colorIndexes[Dark] = rW;
}
else if (mIsPressed)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rB;
colorIndexes[Corner] = rB;
colorIndexes[Light] = rB;
colorIndexes[TL] = rB;
colorIndexes[Grip] = rW;
colorIndexes[BR] = rB;
colorIndexes[Dark] = rB;
}
else // normal
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = rW;
colorIndexes[Corner] = rW;
colorIndexes[Light] = rW;
colorIndexes[TL] = rW;
colorIndexes[Grip] = rB;
colorIndexes[BR] = rW;
colorIndexes[Dark] = rW;
}
}
if (mIsHorizontal)
{
::SetPt(&drawDirection, 0, 1);
::SetPt(&moveDirection, 1, 0);
lineLength = r.bottom - r.top - 11;
propExtra = MaxSInt16(0, r.right - r.left - 15);
}
else
{
::SetPt(&drawDirection, 1, 0);
::SetPt(&moveDirection, 0, 1);
lineLength = r.right - r.left - 11;
propExtra = MaxSInt16(0, r.bottom - r.top - 15);
}
PolyHandle pointerPoly = ::OpenPoly();
this->BuildPointerIndicator(indicatorRect);
::ClosePoly();
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::PaintPoly(pointerPoly);
::RGBForeColor(&gAGARamp[colorIndexes[Frame]]);
::FramePoly(pointerPoly);
::KillPoly(pointerPoly);
if (mIsHorizontal)
{
if (RuntimeJustify(mJustification) == teFlushLeft)
{
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
::Line(0, 0);
::MoveTo(r.right - 2, r.top + 2);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::LineTo(r.right - 2, r.top + 9);
::Line(-5, 5);
::Line(-2 - propExtra, 0);
::Line(-5, -5);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::LineTo(r.left + 1, r.top + 2);
::Line(1, -1);
::LineTo(r.right - 3, r.top + 1);
}
else
{
::MoveTo(r.right - 6, r.top + 2);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::Line(4, 4);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 2, r.bottom - 2);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::Line(0, -7);
::Line(5, -5);
::Line(1 + propExtra, 0);
::MoveTo(r.left + 6, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
::Line(0, 0);
::Move(-5, 5);
::Line(0, 0);
}
}
else
{
if (RuntimeJustify(mJustification) == teFlushLeft)
{
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
::Line(0, 0);
::MoveTo(r.left + 1, r.bottom - 3);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::LineTo(r.left + 1, r.top + 2);
::Line(1, -1);
::Line(7, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::Line(4, 4);
::Line(0, 2 + propExtra);
::Line(-5, 5);
::Line(-7, 0);
}
else
{
::MoveTo(r.left + 2, r.top + 9 + propExtra);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::Line(4, 4);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.right - 2, r.top + 2);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::Line(-7, 0);
::Line(-5, 5);
::Line(0, 1 + propExtra);
::Move(0, - (1 + propExtra));
::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
::Line(0, 0);
::Move(5, -5);
::Line(0, 0);
}
}
if (mEnabled)
{
::MoveTo(r.left + 3 + (moveDirection.h * (((r.right - r.left) / 2) - 6)),
r.top + 3 + (moveDirection.v * (((r.bottom - r.top) / 2) - 6)));
if (RuntimeJustify(mJustification) == teFlushRight)
::Move(2 * drawDirection.h, 2 * drawDirection.v);
if (! deep)
::Move(moveDirection.h, moveDirection.v);
for (SInt32 i = 0; i < 3; i++)
{
::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
::Line(drawDirection.h, drawDirection.v);
::RGBForeColor(&gAGARamp[colorIndexes[Grip]]);
::Line(drawDirection.h * (lineLength-1), drawDirection.v * (lineLength-1));
::Move(moveDirection.h, moveDirection.v);
::Move(drawDirection.h, drawDirection.v);
::RGBForeColor(&gAGARamp[colorIndexes[Dark]]);
::Line(- (drawDirection.h * lineLength), - (drawDirection.v * lineLength));
::Move(moveDirection.h, moveDirection.v);
::Move(- drawDirection.h, - drawDirection.v);
}
}
if (isGhost && deep)
{
// Draw the little see-thru track slides.
// They run inverse draw direction from the grip lines.
// To handle proportional indicators, we need to vary
// the length of the track slides on the flat part.
SInt32 wholeFlatLength;
SInt32 firstFlatLength;
SInt32 remainingFlatLength;
if (mIsHorizontal)
wholeFlatLength = r.right - r.left - 10;
else
wholeFlatLength = r.bottom - r.top - 10;
firstFlatLength = wholeFlatLength / 2;
remainingFlatLength = wholeFlatLength - firstFlatLength; // don't round down twice
::RGBForeColor(&gAGARamp[r11]);
::MoveTo(r.left + (drawDirection.h * 4), r.top + (drawDirection.v * 4));
for (UInt32 i = 0; i < 2; i++)
{
if (RuntimeJustify(mJustification) == teFlushRight)
::Move(3 * drawDirection.h, 3 * drawDirection.v);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r5]);
::Line(moveDirection.h * firstFlatLength, moveDirection.v * firstFlatLength);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r9]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r9]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r2]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r9]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r5]);
::Line(moveDirection.h * remainingFlatLength, moveDirection.v * remainingFlatLength);
::RGBForeColor(&gAGARamp[r7]);
::Line(moveDirection.h, moveDirection.v);
::RGBForeColor(&gAGARamp[r11]);
::Line(0, 0);
::MoveTo(r.left + (drawDirection.h * 8), r.top + (drawDirection.v * 8));
}
}
}
}
void AGASlider::BuildPointerIndicator(Rect* indicatorRect)
{
// Perform the QuickDraw framing commands to build the
// pointy indicator. This function is called while wrapped
// in polygon or region building calls. The caller will
// use the resulting polygon or region to frame, fill,
// or clip.
Rect r = *indicatorRect;
SInt16 propExtra;
if (mIsHorizontal)
{
propExtra = MaxSInt16(0, r.right - r.left - 15);
if (RuntimeJustify(mJustification) == teFlushLeft)
{
::MoveTo(r.right - 1, r.top + 1);
::LineTo(r.right - 1, r.bottom - 7);
::Line(-6, 6);
::Line(-2 - propExtra, 0);
::Line(-6, -6);
::LineTo(r.left, r.top + 1);
::Line(1, -1);
::LineTo(r.right - 2, r.top);
::Line(1, 1);
}
else
{
::MoveTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top + 6);
::Line(6, -6);
::Line(2 + propExtra, 0);
::Line(6, 6);
::LineTo(r.right - 1, r.bottom - 2);
::Line(-1, 1);
::LineTo(r.left + 1, r.bottom - 1);
::Line(-1, -1);
}
}
else
{
propExtra = MaxSInt16(0, r.bottom - r.top - 15);
if (RuntimeJustify(mJustification) == teFlushLeft)
{
::MoveTo(r.left + 1, r.top);
::LineTo(r.right - 7, r.top);
::Line(6, 6);
::Line(0, 2 + propExtra);
::Line(-6, 6);
::LineTo(r.left + 1, r.bottom - 1);
::Line(-1, -1);
::LineTo(r.left, r.top + 1);
::Line(1, -1);
}
else
{
::MoveTo(r.right - 2, r.bottom - 1);
::LineTo(r.left + 6, r.bottom - 1);
::Line(-6, -6);
::Line(0, -2 - propExtra);
::Line(6, -6);
::LineTo(r.right - 2, r.top);
::Line(1, 1);
::LineTo(r.right - 1, r.bottom - 2);
::Line(-1, 1);
}
}
}
void AGASlider::RemoveIndicator(SInt32 newValue)
{
// Draw the background to remove the indicator
// at the specified value.
//
// Set clipping so we only draw the track to
// wipe out the old indicator, but not where
// the new indicator will get drawn anyway.
// This reduces flicker. Polygon geometry makes
// tweaking necessary and still imperfect.
//
::GetClip(mgSavedIndicatorClip);
if (newValue != mValue)
{
Rect oldIndicatorBox;
Rect newIndicatorBox;
this->GetIndicatorBox(mValue, &oldIndicatorBox);
this->GetIndicatorBox(newValue, &newIndicatorBox);
if (mSliderKind == kRectSlider)
{
::RectRgn(mgOldIndicatorClip, &oldIndicatorBox);
::RectRgn(mgNewIndicatorClip, &newIndicatorBox);
}
else
{
//
// For optimal clipping, because of polygon and
// region geometry, we have to tweak the regions
// a little bit.
//
RgnHandle tempRegion = ::NewRgn();
::OpenRgn();
this->BuildPointerIndicator(&oldIndicatorBox);
::CloseRgn(mgOldIndicatorClip);
::CopyRgn(mgOldIndicatorClip, tempRegion);
::OffsetRgn(tempRegion, 1, 1);
::InsetRgn(tempRegion, -1, -1);
::UnionRgn(mgOldIndicatorClip, tempRegion, mgOldIndicatorClip);
::OpenRgn();
this->BuildPointerIndicator(&newIndicatorBox);
::CloseRgn(mgNewIndicatorClip);
::CopyRgn(mgNewIndicatorClip, tempRegion);
::UnionRgn(mgNewIndicatorClip, tempRegion, mgNewIndicatorClip);
::DisposeRgn(tempRegion);
}
::DiffRgn(mgOldIndicatorClip, mgNewIndicatorClip, mgOldIndicatorClip);
::SetClip(mgOldIndicatorClip);
}
this->DrawIndicatorTrack();
::SetClip(mgSavedIndicatorClip);
}
void AGASlider::RemoveGhost(SInt32 /*newValue*/)
{
// Draw the background necessary to remove the
// ghost indicator while not removing the solid
// value indicator.
Rect r;
RgnHandle savedClip = ::NewRgn();
::GetClip(savedClip);
this->GetIndicatorBox(mGhostValue, &r);
::ClipRect(&r);
this->DrawIndicatorTrack();
this->DrawIndicator();
::SetClip(savedClip);
::DisposeRgn(savedClip);
}
void AGASlider::GetTrackFrame(Rect* trackFrame, Boolean includeBackground)
{
// Return the rectangle that bounds just the indicator
// track, including shading pixels but not the area covered
// by the indicator itself.
Boolean leftJustify = (RuntimeJustify(mJustification) == teFlushLeft);
*trackFrame = mBounds;
if (mIsHorizontal)
{
if (leftJustify)
{
trackFrame->top += 4;
trackFrame->bottom = trackFrame->top + 7;
}
else
{
trackFrame->bottom -= 4;
trackFrame->top = trackFrame->bottom - 7;
}
if (includeBackground)
{
trackFrame->top -= leftJustify ? 4 : 6;
trackFrame->bottom += leftJustify ? 6 : 4;
}
}
else
{
if (leftJustify)
{
trackFrame->left += 4;
trackFrame->right = trackFrame->left + 7;
}
else
{
trackFrame->right -= 4;
trackFrame->left = trackFrame->right - 7;
}
if (includeBackground)
{
trackFrame->left -= leftJustify ? 4 : 6;
trackFrame->right += leftJustify ? 6 : 4;
}
}
}
void AGASlider::GetIndicatorBox(SInt32 indicatorValue, Rect* indicatorBox)
{
// Return the box that defines the indicator's location
// given the specified indicator value.
Rect r = mBounds;
SInt32 startPt;
SInt32 valuePt;
SInt32 stopPt;
this->GetIndicatorSpan(indicatorValue, &startPt, &valuePt, &stopPt);
if (mIsHorizontal)
{
r.left = startPt;
r.right = stopPt;
if (RuntimeJustify(mJustification) == teFlushLeft)
{
if (mSliderKind == kPointerSlider)
r.top++;
r.bottom = r.top + kIndicatorWidth;
}
else
{
if (mSliderKind == kPointerSlider)
r.bottom--;
r.top = r.bottom - kIndicatorWidth;
}
}
else
{
r.top = startPt;
r.bottom = stopPt;
if (RuntimeJustify(mJustification) == teFlushLeft)
{
if (mSliderKind == kPointerSlider)
r.left++;
r.right = r.left + kIndicatorWidth;
}
else
{
if (mSliderKind == kPointerSlider)
r.right--;
r.left = r.right - kIndicatorWidth;
}
}
*indicatorBox = r;
}
SInt32 AGASlider::GetIndicatorPixelRange(SInt32* proportionalIndicatorPixels)
{
// Return the pixel range that the center point of the indicator
// can travel along the track, and also return the amount of
// range reduction that is caused by proportional indicator growth.
// Non-proportional indicators use the full track range, minus
// the size of the indicator itself.
SInt32 range;
SInt32 indicatorInset = (mSliderKind == kRectSlider) ? kRectIndicatorPixelInset : kPointerIndicatorPixelInset;
*proportionalIndicatorPixels = 0;
if (mIsHorizontal)
range = mBounds.right - mBounds.left - (2 * (kEndGapSize + indicatorInset)) + 1;
else
range = mBounds.bottom - mBounds.top - (2 * (kEndGapSize + indicatorInset)) + 1;
if (mIsProportional)
{
SInt32 pagePixels;
pagePixels =
(range * (((float) mPageSize) / ((float) (mMaximum - mMinimum))));
if (pagePixels > 0)
{
range -= pagePixels;
*proportionalIndicatorPixels = pagePixels;
}
}
return range;
}
void AGASlider::GetIndicatorPixelEnds(SInt32* startPt, SInt32* stopPt)
{
// Return the start and end pixel locations of the indicator
// track traveled by the center point of the indicator.
SInt32 dontCare;
SInt32 range = this->GetIndicatorPixelRange(&dontCare);
if (mIsHorizontal)
*startPt = ((mBounds.left + mBounds.right) / 2) - (range / 2) - 1;
else
*startPt = ((mBounds.top + mBounds.bottom) / 2) - (range / 2) - 1;
*stopPt = *startPt + range; // avoid rounding of 1/2 pixel twice
}
void AGASlider::GetIndicatorSpan(SInt32 value, SInt32* startPt, SInt32* valuePt, SInt32* stopPt)
{
// Return the pixel locations of the indicator's ends and value.
SInt32 proportionalIndicatorPixels;
SInt32 trackStart;
SInt32 trackStop;
SInt32 trackRange = this->GetIndicatorPixelRange(&proportionalIndicatorPixels);
SInt32 indicatorInset = (mSliderKind == kRectSlider) ? kRectIndicatorPixelInset : kPointerIndicatorPixelInset;
this->GetIndicatorPixelEnds(&trackStart, &trackStop);
*valuePt = trackStart +
(trackRange * (((float) (value - mMinimum)) / ((float) (mMaximum - mMinimum))));
*startPt = *valuePt - indicatorInset - (proportionalIndicatorPixels / 2);
*stopPt = *startPt + (2 * indicatorInset) + proportionalIndicatorPixels + 1;
}
void AGASlider::DisposeLabels()
{
// Release the memory allocated for slider labels.
if (mLabelStringHandles != NULL)
{
UInt32 numHandles = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
for (UInt32 i = 0; i < numHandles; i++)
::DisposeHandle((Handle) ((StringHandle*)(*mLabelStringHandles))[i]);
::DisposeHandle(mLabelStringHandles);
}
}
//
// AGAPopupMenu ---------------------------------------------------------------
//
// This class implements a standard popup menu look, and handles the
// mouse by calling PopUpMenuSelect such that the visible menu is
// located where the AGA says it should.
//
AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& titleStyle, const AGATextStyle& textStyle, WidthAdjust adjustment)
: AGAObject(bounds)
{
// Construct without a menu installed.
mMenuID = 0;
mMenuRef = NULL;
mMenuRefDisposalKind = kDontDispose;
mCurrentItemNo = 1;
mWidthAdjust = adjustment;
mTitleStyle = titleStyle;
mTextStyle = textStyle;
AGA_PLstrcpy(mTitle, title);
mTitleOffset = titleOffset;
mTitleJustification = titleJustification;
}
AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& titleStyle, const AGATextStyle& textStyle, WidthAdjust adjustment, MenuRef itsMenuRef, DisposalKind menuRefDisposalKind)
: AGAObject(bounds)
{
// Construct with specified MenuRef.
if (itsMenuRef == NULL)
mMenuID = 0;
else
mMenuID = (**itsMenuRef).menuID;
mMenuRef = itsMenuRef;
mMenuRefDisposalKind = menuRefDisposalKind;
mCurrentItemNo = 1;
mWidthAdjust = adjustment;
mTitleStyle = titleStyle;
mTextStyle = textStyle;
AGA_PLstrcpy(mTitle, title);
mTitleOffset = titleOffset;
mTitleJustification = titleJustification;
}
AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& titleStyle, const AGATextStyle& textStyle, WidthAdjust adjustment, SInt16 itemsStringListID, SInt16 newMenuID)
: AGAObject(bounds)
{
// Construct with menu built from strings in a 'STR#' resource.
mMenuID = newMenuID;
mMenuRef = ::NewMenu(newMenuID, "\pAGA");
mMenuRefDisposalKind = kDispose;
mCurrentItemNo = 1;
mWidthAdjust = adjustment;
mTitleStyle = titleStyle;
mTextStyle = textStyle;
AGA_PLstrcpy(mTitle, title);
mTitleOffset = titleOffset;
mTitleJustification = titleJustification;
Handle stringListHandle = ::GetResource('STR#', itemsStringListID);
if (stringListHandle != NULL)
{
SInt16 numStrings = **((SInt16 **) stringListHandle);
for (SInt16 stringIndex = 1; stringIndex <= numStrings; stringIndex++)
{
Str255 aString;
::GetIndString(aString, itemsStringListID, stringIndex);
// Use SetMenuItemText to avoid metacharacter interpretation.
::AppendMenu(mMenuRef, "\pXXX");
::SetMenuItemText(mMenuRef, stringIndex, aString);
}
}
}
AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& titleStyle, const AGATextStyle& textStyle, WidthAdjust adjustment, ResType appendResourceType, SInt16 newMenuID)
: AGAObject(bounds)
{
// Construct with menu built from specified appended resource type.
// Typical use is for a Fonts menu, using resource type 'FOND'.
mMenuID = newMenuID;
mMenuRef = ::NewMenu(newMenuID, "\pAGA");
mMenuRefDisposalKind = kDispose;
mCurrentItemNo = 1;
mWidthAdjust = adjustment;
mTitleStyle = titleStyle;
mTextStyle = textStyle;
AGA_PLstrcpy(mTitle, title);
mTitleOffset = titleOffset;
mTitleJustification = titleJustification;
::AppendResMenu(mMenuRef, appendResourceType);
}
AGAPopupMenu::~AGAPopupMenu()
{
// Destruct by cleaning up the menu data.
// This depends on how the menu was created.
this->DisposeExistingMenuRef();
}
void AGAPopupMenu::DisposeExistingMenuRef()
{
// Clean up the menu data based on how it was created
// or how the client code specified.
if (mMenuRef != NULL)
{
if (mMenuRefDisposalKind == kDispose)
::DisposeMenu(mMenuRef);
else if (mMenuRefDisposalKind == kRelease)
::ReleaseResource((Handle) mMenuRef);
}
mMenuRefDisposalKind = kDontDispose;
}
void AGAPopupMenu::SetMenuRef(MenuRef itsMenuRef, DisposalKind menuRefDisposalKind)
{
// Install the specified MenuRef.
this->DisposeExistingMenuRef();
if (itsMenuRef == NULL)
mMenuID = 0;
else
mMenuID = (**itsMenuRef).menuID;
mMenuRef = itsMenuRef;
mMenuRefDisposalKind = menuRefDisposalKind;
mCurrentItemNo = 1;
}
void AGAPopupMenu::SetWidthAdjustment(WidthAdjust adjustment)
{
// Set the width adjustment, which determines how wide
// the closed menu appears.
mWidthAdjust = adjustment;
}
void AGAPopupMenu::DrawObject()
{
// Draw the unpressed popup menu "button".
this->DrawButton(kNotPressed);
}
Boolean AGAPopupMenu::TrackMouse(Point /*mouseLocation*/)
{
if (! mEnabled)
return false;
// Track the mouse in the popup, and return true
// if it caused the current popup selection to change.
Boolean selectionChanged;
SInt32 menuResult;
Point globalOrigin;
this->DrawButton(kPressed);
::SetPt(&globalOrigin, mBounds.left + mTitleOffset, mBounds.bottom);
::LocalToGlobal(&globalOrigin);
::InsertMenu(mMenuRef, -1); // put it in the hierarchical list
if ((mTextStyle.mFontNum != 0) || ((mTextStyle.mFontSize != 0) && (mTextStyle.mFontSize != 12)))//sizer.mIsCustom)
::SetItemMark(mMenuRef, mCurrentItemNo, '•');
else
::CheckItem(mMenuRef, mCurrentItemNo, true);
{ // create scope so AGACustomPopupMenuSizer is destructed right away
AGACustomPopupMenuSizer sizer(mTextStyle.mFontNum, mTextStyle.mFontSize);
menuResult = ::PopUpMenuSelect(mMenuRef, globalOrigin.v, globalOrigin.h + 1, 1);
}
::CheckItem(mMenuRef, mCurrentItemNo, false);
::DeleteMenu((**mMenuRef).menuID); // get it out of the hierarchical list
selectionChanged = (menuResult != 0);
if (selectionChanged)
this->SetCurrentItemNo(menuResult & 0x0000FFFF, kDontRedraw);
this->DrawButton(kNotPressed);
return selectionChanged;
}
SInt16 AGAPopupMenu::GetCurrentItemNo()
{
// Return the currently selected item index (1-based).
return mCurrentItemNo;
}
void AGAPopupMenu::SetCurrentItemNo(SInt16 newItemNo, Boolean redraw)
{
// Set the current item index (1-based), optionally redraw.
mCurrentItemNo = newItemNo;
if (redraw)
this->DrawButton(kNotPressed);
}
void AGAPopupMenu::GetCurrentItemText(StringPtr itemText)
{
// Return the menu item text of the currently selected item.
itemText[0] = 0;
if (mMenuRef != NULL)
::GetMenuItemText(mMenuRef, this->GetCurrentItemNo(), itemText);
}
Boolean AGAPopupMenu::SetCurrentItemText(StringPtr itemTextToMatch, Boolean redraw)
{
// Set the current item index to the item whose text
// matches the specified string. Optionally redraw.
Boolean wasMatchFound = false;
SInt16 numItems = 0;
if (mMenuRef != NULL)
numItems = ::CountMenuItems(mMenuRef);
for (SInt16 itemIndex = 1; itemIndex <= numItems; itemIndex++)
{
Str255 itemText;
::GetMenuItemText(mMenuRef, itemIndex, itemText);
if (::EqualString(itemText, itemTextToMatch, true, true))
{
wasMatchFound = true;
this->SetCurrentItemNo(itemIndex, redraw);
break;
}
}
return wasMatchFound;
}
void AGAPopupMenu::SetTitle(StringPtr newTitle, Boolean redraw)
{
// Install the new title. Optionally redraw.
AGA_PLstrcpy(mTitle, newTitle);
if (redraw)
this->DrawButton(kNotPressed);
}
void AGAPopupMenu::DrawButton(Boolean pressed)
{
// Draw the popup button in the specified state.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (! mEnabled)
this->DrawButtonDisabled(deep);
else if (pressed)
this->DrawButtonPressed(deep);
else
this->DrawButtonNormal(deep);
}
}
void AGAPopupMenu::DrawButtonNormal(Boolean deep)
{
AGADrawingEnvironment env;
// Draw the popup button in enabled/unpressed state.
Rect r;
Str255 currentItemText;
this->GetCurrentItemText(currentItemText);
this->GetButtonBounds(&r);
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r2]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(r.right - r.left - 6, 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, r.bottom - r.top - 6);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(- (r.right - r.left - 6), 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, -(r.bottom - r.top - 6));
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
if (r.right - r.left > kPopupArrowSectionWidth)
{
// Add flat section inner pixels.
::RGBForeColor(&gAGARamp[rW]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 2);
::Move(1, -1);
::LineTo(r.right - kPopupArrowSectionWidth, r.top + 1);
::RGBForeColor(&gAGARamp[r1]);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(r.left + 2, r.bottom - 2);
::LineTo(r.right - kPopupArrowSectionWidth, r.bottom - 2);
::LineTo(r.right - kPopupArrowSectionWidth, r.top + 2);
// Add arrow section left corners
::RGBForeColor(&gAGARamp[r4]);
::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.bottom - 2);
::Line(0, 0);
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.top + 1);
::Line(0, 0);
}
// Add arrow section shading.
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 2);
::LineTo(r.right - 3, r.bottom - 2);
::Line(0, -1);
::Line(1, 0);
::LineTo(r.right - 2, r.top + 3);
::Move(-1, -2);
::RGBForeColor(&gAGARamp[r4]);
::Line(1, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(-1, 1);
::LineTo(r.right - 3, r.bottom - 4);
::Move(-1, 1);
::LineTo(r.right - kPopupArrowSectionWidth + 3, r.bottom - 3);
::RGBForeColor(&gAGARamp[rW]);
::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 4);
::LineTo(r.right - kPopupArrowSectionWidth + 2, r.top + 2);
::LineTo(r.right - 4, r.top + 2);
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rW]);
::PaintRoundRect(&r, 7, 7);
::RGBForeColor(&gAGARamp[rB]);
::FrameRoundRect(&r, 7, 7);
}
// Add arrow.
::RGBForeColor(&gAGARamp[rB]);
::MoveTo(r.right - kPopupArrowSectionWidth + 6, r.top + ((r.bottom - r.top) / 2) - 2);
::Line(8, 0);
::Move(-1, 1);
::Line(-6, 0);
::Move(1, 1);
::Line(4, 0);
::Move(-1, 1);
::Line(-2, 0);
::Line(1, 1);
if (r.right - r.left > kPopupArrowSectionWidth)
{
// Draw the current item text.
r.left += 7;
r.right -= kPopupArrowSectionWidth;
AGAStringOut(currentItemText, &r, truncEnd, teFlushDefault, kNormalOutput, deep, mTextStyle);
}
// If the popup has a title, draw it next to the button.
if (mTitle[0] != 0)
{
this->GetTitleBounds(&r);
AGAStringOut(mTitle, &r, truncEnd, mTitleJustification, kNormalOutput, deep, mTitleStyle);
}
}
void AGAPopupMenu::DrawButtonPressed(Boolean deep)
{
AGADrawingEnvironment env;
// Draw the popup button in enabled/pressed state.
Rect r;
Str255 currentItemText;
this->GetCurrentItemText(currentItemText);
this->GetButtonBounds(&r);
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r9]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(r.right - r.left - 6, 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, r.bottom - r.top - 6);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, 0);
::RGBForeColor(&gAGARamp[rB]);
::Line(- (r.right - r.left - 6), 0);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, 0);
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
::Move(0, -1);
::RGBForeColor(&gAGARamp[rB]);
::Line(0, -(r.bottom - r.top - 6));
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
if (r.right - r.left > kPopupArrowSectionWidth)
{
// Add flat section inner pixels.
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 2);
::Line(1, 0);
::Line(0, -1);
::LineTo(r.right - kPopupArrowSectionWidth, r.top + 1);
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left + 2, r.bottom - 2);
::LineTo(r.right - kPopupArrowSectionWidth, r.bottom - 2);
::LineTo(r.right - kPopupArrowSectionWidth, r.top + 2);
// Add arrow section left corners
::RGBForeColor(&gAGARamp[r11]);
::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.bottom - 2);
::Line(0, 0);
::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.top + 1);
::Line(0, 0);
}
// Add arrow section shading.
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 2);
::LineTo(r.right - 3, r.bottom - 2);
::Line(0, -1);
::Line(1, 0);
::LineTo(r.right - 2, r.top + 2);
::Move(-1, 1);
::RGBForeColor(&gAGARamp[r8]);
::LineTo(r.right - 3, r.bottom - 4);
::Move(-1, 1);
::LineTo(r.right - kPopupArrowSectionWidth + 3, r.bottom - 3);
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 4);
::LineTo(r.right - kPopupArrowSectionWidth + 2, r.top + 2);
::LineTo(r.right - 4, r.top + 2);
::RGBForeColor(&gAGARamp[r11]);
::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.bottom - 3);
::LineTo(r.right - kPopupArrowSectionWidth + 1, r.top + 2);
::Move(1, -1);
::LineTo(r.right - 3, r.top + 1);
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rB]);
::PaintRoundRect(&r, 7, 7);
}
// Add arrow.
::RGBForeColor(&gAGARamp[rW]);
::MoveTo(r.right - kPopupArrowSectionWidth + 6, r.top + ((r.bottom - r.top) / 2) - 2);
::Line(8, 0);
::Move(-1, 1);
::Line(-6, 0);
::Move(1, 1);
::Line(4, 0);
::Move(-1, 1);
::Line(-2, 0);
::Line(1, 1);
if (r.right - r.left > kPopupArrowSectionWidth)
{
// Draw the current item text.
r.left += 7;
r.right -= kPopupArrowSectionWidth;
AGAStringOut(currentItemText, &r, truncEnd, teFlushDefault, kInverseOutput, deep, mTextStyle);
}
// (No need to draw the title, since it does not change
// upon pressing the button.)
}
void AGAPopupMenu::DrawButtonDisabled(Boolean deep)
{
AGADrawingEnvironment env;
// Draw the popup button in disabled/unpressed state.
Rect r;
Str255 currentItemText;
this->GetCurrentItemText(currentItemText);
this->GetButtonBounds(&r);
::PenSize(1, 1);
if (deep)
{
// Fill the interior.
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[r2]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
// Draw the frame.
::MoveTo(r.left + 1, r.top + 1);
::RGBForeColor(&gAGARamp[r7]);
::Line(0, 0);
::Move(1, -1);
::Line(0, 0);
::Move(1, 0);
::Line(r.right - r.left - 6, 0);
::Line(0, 0);
::Move(1, 1);
::Line(0, 0);
::Move(1, 1);
::Line(0, 0);
::Move(0, 1);
::Line(0, r.bottom - r.top - 6);
::Line(0, 0);
::Move(-1, 1);
::Line(0, 0);
::Move(-1, 1);
::Line(0, 0);
::Move(-1, 0);
::Line(- (r.right - r.left - 6), 0);
::Line(0, 0);
::Move(-1, -1);
::Line(0, 0);
::Move(-1, -1);
::Line(0, 0);
::Move(0, -1);
::Line(0, -(r.bottom - r.top - 6));
::Line(0, 0);
if (r.right - r.left > kPopupArrowSectionWidth)
{
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(r.right - kPopupArrowSectionWidth, r.bottom - 2);
::LineTo(r.right - kPopupArrowSectionWidth, r.top + 2);
}
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rW]);
::PaintRoundRect(&r, 7, 7);
::RGBForeColor(&gAGARamp[rB]);
::FrameRoundRect(&r, 7, 7);
}
// Add arrow.
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.right - kPopupArrowSectionWidth + 6, r.top + ((r.bottom - r.top) / 2) - 2);
::Line(8, 0);
::Move(-1, 1);
::Line(-6, 0);
::Move(1, 1);
::Line(4, 0);
::Move(-1, 1);
::Line(-2, 0);
::Line(1, 1);
if (r.right - r.left > kPopupArrowSectionWidth)
{
// Draw the current item text.
r.left += 7;
r.right -= kPopupArrowSectionWidth;
AGAStringOut(currentItemText, &r, truncEnd, teFlushDefault, kDisabledOutput, deep, mTextStyle);
}
// If the popup has a title, draw it next to the button.
if (mTitle[0] != 0)
{
this->GetTitleBounds(&r);
AGAStringOut(mTitle, &r, truncEnd, mTitleJustification, kDisabledOutput, deep, mTitleStyle);
}
if (! deep)
{
::RGBForeColor(&gAGARamp[rB]);
::PenPat(&qd.gray);
::PenMode(patBic);
::PaintRect(&mBounds);
::PenNormal();
}
}
void AGAPopupMenu::GetButtonBounds(Rect* buttonBounds)
{
// Return the bounds of the popup button. We may need
// to check the actual menu's width, depending on the
// width adjustment specifier.
*buttonBounds = mBounds;
buttonBounds->left += mTitleOffset;
if ((mMenuRef != NULL) && (mWidthAdjust != kFixedWidth))
{
AGACustomPopupMenuSizer sizer(mTextStyle.mFontNum, mTextStyle.mFontSize);
::CalcMenuSize(mMenuRef);
buttonBounds->right = MinSInt16(mBounds.right, buttonBounds->left + 3 + (**mMenuRef).menuWidth + mWidthAdjust);
}
}
void AGAPopupMenu::GetTitleBounds(Rect* titleBounds)
{
// Return the bounds of the title area.
*titleBounds = mBounds;
titleBounds->right = titleBounds->left + mTitleOffset - 3;
}
//
// AGACustomPopupMenuSizer ---------------------------------------------------------------
//
// Stack-based object to hack in a custom popup menu font/size
// around a call to PopUpMenuSelect or CalcMenuSize.
//
AGACustomPopupMenuSizer::AGACustomPopupMenuSizer(SInt16 fontNum, SInt16 fontSize)
{
mCustomFontNum = fontNum;
mCustomFontSize = fontSize;
mIsCustom = (fontNum != 0) || ((fontSize != 0) && (fontSize != 12));
this->SaveEnvironment();
this->InstallCustomEnvironment();
}
AGACustomPopupMenuSizer::~AGACustomPopupMenuSizer()
{
this->RestoreEnvironment();
}
void AGACustomPopupMenuSizer::SaveEnvironment()
{
if (mIsCustom)
{
mSavedFontNum = ::LMGetSysFontFam();
mSavedFontSize = ::LMGetSysFontSize();
}
}
void AGACustomPopupMenuSizer::RestoreEnvironment()
{
if (mIsCustom)
{
::LMSetSysFontFam(mSavedFontNum);
::LMSetSysFontSize(mSavedFontSize);
::LMSetLastSPExtra(-1);
}
}
void AGACustomPopupMenuSizer::InstallCustomEnvironment()
{
if (mIsCustom)
{
::LMSetSysFontFam(mCustomFontNum);
::LMSetSysFontSize(mCustomFontSize);
::LMSetLastSPExtra(-1);
}
}
//
// AGALittleArrows ---------------------------------------------------------------
//
// This class implements a little arrows control.
//
AGALittleArrows::AGALittleArrows(Rect* bounds)
: AGAObject(bounds)
{
mNotificationRoutine = NULL;
mUserData = 0;
}
AGALittleArrows::~AGALittleArrows()
{
}
void AGALittleArrows::InstallNotificationRoutine(AGALittleArrowsNotifyPtr notificationRoutine, void* userData)
{
// Install the supplied function pointer and user data to
// be called during notification.
mNotificationRoutine = notificationRoutine;
mUserData = userData;
}
void AGALittleArrows::DrawObject()
{
// Draw the arrows in normal unpressed state.
this->DrawButton(kNoArrowPressed);
}
Boolean AGALittleArrows::TrackMouse(Point mouseLocation)
{
if (! mEnabled)
return false;
// Track the mouse in the appropriate arrow. Little arrows
// always return true because the tracking is always successful.
return this->TrackPart(mouseLocation, this->TrackTestPart(mouseLocation));
}
void AGALittleArrows::DrawButton(SInt32 pressedPart)
{
AGADrawingEnvironment env;
// Draw the arrows in the specified press state. The
// state may indicate that either or no arrow is pressed.
enum { Frame, Fill, TL, BR, Arrow, kNumArrowColors };
UInt8 colorIndexes[kNumArrowColors];
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = mBounds;
r.right = r.left + kLittleArrowWidth;
r.bottom = r.top + kLittleArrowHeight;
for (UInt32 i = 0; i < 2; i++)
{
if (deep)
{
if (mEnabled)
{
if (((pressedPart == kUpArrowPressed) && (i == 0)) ||
((pressedPart == kDownArrowPressed) && (i == 1)))
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = r8;
colorIndexes[TL] = r10;
colorIndexes[BR] = r6;
colorIndexes[Arrow] = rW;
}
else if (((pressedPart != kUpArrowPressed) && (i == 0)) ||
((pressedPart != kDownArrowPressed) && (i == 1)))
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = r2;
colorIndexes[TL] = rW;
colorIndexes[BR] = r5;
colorIndexes[Arrow] = rB;
}
}
else // disabled
{
colorIndexes[Frame] = r7;
colorIndexes[Fill] = r2;
colorIndexes[TL] = r2;
colorIndexes[BR] = r2;
colorIndexes[Arrow] = r7;
}
// These (1-i) and i uses here are to round off the top corners
// of the top frame (i=0) and round off the bottom corners of
// the bottom frame (i=1).
::RGBForeColor(&gAGARamp[colorIndexes[Frame]]);
::MoveTo(r.left + (1-i), r.top);
::LineTo(r.right - 1 - (1-i), r.top);
::Move(1-i, 1-i);
::LineTo(r.right -1, r.bottom - 1 - i);
::Move(-i, i);
::LineTo(r.left + i, r.bottom - 1);
::Move(-i, -i);
::LineTo(r.left, r.top + (1-i));
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 3, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
::MoveTo(r.left + 2, r.bottom - 2);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.right - 2, r.top + 2);
::RGBForeColor(&gAGARamp[colorIndexes[Arrow]]);
}
else // 1-bit
{
if (((pressedPart == kUpArrowPressed) && (i == 0)) ||
((pressedPart == kDownArrowPressed) && (i == 1)))
{
::RGBForeColor(&gAGARamp[rB]);
::InsetRect(&r, 1, 1);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
::RGBForeColor(&gAGARamp[rW]);
}
else
{
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
::RGBForeColor(&gAGARamp[rB]);
::MoveTo(r.left + (1-i), r.top);
::LineTo(r.right - 1 - (1-i), r.top);
::Move(1-i, 1-i);
::LineTo(r.right -1, r.bottom - 1 - i);
::Move(-i, i);
::LineTo(r.left + i, r.bottom - 1);
::Move(-i, -i);
::LineTo(r.left, r.top + (1-i));
}
}
::MoveTo(r.left + 3, r.top + 7 - (i*3));
::Line(6, 0);
::Move(-1, -1 + (2*i));
::Line(-4, 0);
::Move(1, -1 + (2*i));
::Line(2, 0);
::Move(-1, -1 + (2*i));
::Line(0, 0);
::OffsetRect(&r, 0, kLittleArrowHeight - 1);
}
if ((! mEnabled) && ! deep)
{
::RGBForeColor(&gAGARamp[rB]);
::PenPat(&qd.gray);
::PenMode(patBic);
::PaintRect(&mBounds);
::PenNormal();
}
}
}
Boolean AGALittleArrows::TrackPart(Point /*mouseLocation*/, SInt32 partHit)
{
// Track the mouse in the specified arrow. Little arrows always
// return true because the tracking is always successful.
Boolean wasIn = false;
Boolean isIn = true;
Boolean isButtonDown = true; // ensure at least one time through
Point newMouseLocation;
UInt32 accelerationDelay = 18; // will divide by 2 each time
while (isButtonDown)
{
if (isIn)
this->NotifyDelta(partHit);
::GetMouse(&newMouseLocation); // gives local coordinates
isIn = (this->TrackTestPart(newMouseLocation) == partHit);
if (isIn != wasIn)
this->DrawButton(isIn ? partHit : kNoArrowPressed);
wasIn = isIn;
if (isButtonDown && (accelerationDelay != 0))
{
DelayFutureWhileStillDown(accelerationDelay);
accelerationDelay = accelerationDelay >> 1; // divide by 2
}
isButtonDown = ::StillDown();
}
if (isIn) // if finished IN, restore normal appearance
this->DrawButton(kNoArrowPressed);
return true;
}
SInt32 AGALittleArrows::TrackTestPart(Point mouseLocation)
{
// Return the part value where the mouse would hit.
if ((mouseLocation.h >= mBounds.left + kLittleArrowWidth) ||
(mouseLocation.h < mBounds.left) ||
(mouseLocation.v >= mBounds.top + kLittleArrowTotalHeight) ||
(mouseLocation.v < mBounds.top))
return kNoArrowPressed;
else if (mouseLocation.v < mBounds.top + kLittleArrowHeight)
return kUpArrowPressed;
else
return kDownArrowPressed;
}
void AGALittleArrows::NotifyDelta(SInt32 partHit)
{
// Call the installed notification routine, if any, with
// the installed user data and our part hit, which is the
// value delta (-1 or 1).
if (mNotificationRoutine != NULL)
(*(mNotificationRoutine))(this, partHit, mUserData);
}
//
// AGADisclosureTriangle ---------------------------------------------------------------
//
// This class implements a disclosure triangle.
//
AGADisclosureTriangle::AGADisclosureTriangle(Rect* bounds, Boolean automaticState)
: AGAObject(bounds)
{
// Construct as specified.
mAutomaticState = automaticState;
mIsDisclosed = kClosedState;
}
AGADisclosureTriangle::~AGADisclosureTriangle()
{
}
void AGADisclosureTriangle::DrawObject()
{
// Draw the triangle in the current state.
this->DrawTriangle(mIsDisclosed ? kDTDisclosed : kDTClosed);
}
Boolean AGADisclosureTriangle::TrackMouse(Point mouseLocation)
{
// Let superclass handle tracking, and change our state
// if we have automatic state change turned on.
Boolean wasItHit = AGAObject::TrackMouse(mouseLocation);
if (wasItHit && mAutomaticState)
this->SetStateAnimate(! mIsDisclosed);
return wasItHit;
}
Boolean AGADisclosureTriangle::GetState()
{
// Return the current state.
return mIsDisclosed;
}
void AGADisclosureTriangle::SetState(Boolean isDisclosed, Boolean redraw)
{
// Set the state and optionally redraw.
if (isDisclosed != mIsDisclosed)
{
mIsDisclosed = isDisclosed;
if (redraw)
this->DrawTriangle(mIsDisclosed ? kDTDisclosed : kDTClosed);
}
}
void AGADisclosureTriangle::SetStateAnimate(Boolean isDisclosed)
{
// Set the state, but animate the triangle as it changes
// to the new state.
const SInt32 kAnimationDelay = 4;
if (isDisclosed)
{
this->DrawTriangle(kDTPressedClosed);
DelayFuture(kAnimationDelay);
this->EraseBackground();
this->DrawTriangle(kDTIntermediate);
DelayFuture(kAnimationDelay);
this->EraseBackground();
this->DrawTriangle(kDTPressedDisclosed);
DelayFuture(kAnimationDelay);
this->EraseBackground();
}
else
{
this->DrawTriangle(kDTPressedDisclosed);
DelayFuture(kAnimationDelay);
this->EraseBackground();
this->DrawTriangle(kDTIntermediate);
DelayFuture(kAnimationDelay);
this->EraseBackground();
this->DrawTriangle(kDTPressedClosed);
DelayFuture(kAnimationDelay);
this->EraseBackground();
}
this->SetState(isDisclosed, kRedraw);
}
void AGADisclosureTriangle::SetTrackingState(Boolean isIn)
{
// Draw the triangle pressed or unpressed as specified.
DTAnimationState state;
if (isIn)
state = mIsDisclosed ? kDTPressedDisclosed : kDTPressedClosed;
else
state = mIsDisclosed ? kDTDisclosed : kDTClosed;
this->DrawTriangle(state);
}
void AGADisclosureTriangle::DrawTriangle(DTAnimationState state)
{
AGADrawingEnvironment env;
// Draw the triangle at the specified animation frame.
Point fulcrum;
Point corners[3];
::SetPt(&fulcrum, mBounds.left + 5, mBounds.top + 5);
switch (state)
{
case kDTClosed:
case kDTPressedClosed:
::SetPt(&corners[0], fulcrum.h - 2, fulcrum.v - 5);
::SetPt(&corners[1], fulcrum.h + 3, fulcrum.v);
::SetPt(&corners[2], fulcrum.h - 2, fulcrum.v + 5);
break;
case kDTIntermediate:
::SetPt(&corners[0], fulcrum.h + 3, fulcrum.v - 5);
::SetPt(&corners[1], fulcrum.h + 3, fulcrum.v + 3);
::SetPt(&corners[2], fulcrum.h - 5, fulcrum.v + 3);
break;
case kDTPressedDisclosed:
case kDTDisclosed:
::SetPt(&corners[0], fulcrum.h + 5, fulcrum.v - 2);
::SetPt(&corners[1], fulcrum.h, fulcrum.v + 3);
::SetPt(&corners[2], fulcrum.h - 5, fulcrum.v - 2);
break;
}
// Little trick: tweak state so that disabled state (gray
// fill) is handled by pressed case code below. We already set
// the color so they only set pressed fill color if enabled.
DTAnimationState deepState = state;
if (! mEnabled)
{
if (deepState == kDTClosed)
deepState = kDTPressedClosed;
else
deepState = kDTPressedDisclosed;
}
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
if (mEnabled)
::RGBForeColor(&gAGARamp[rB]);
else
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(corners[0].h, corners[0].v);
::LineTo(corners[1].h, corners[1].v);
::LineTo(corners[2].h, corners[2].v);
::LineTo(corners[0].h, corners[0].v);
switch (deepState)
{
case kDTClosed:
::RGBForeColor(&gAGARamp[rP1]);
::MoveTo(corners[0].h + 1, corners[0].v + 2);
::Line(0, 6);
::RGBForeColor(&gAGARamp[rP2]);
::Line(1, -1);
::Line(0, -4);
::Line(1, 1);
::Line(0, 1);
::Move(1, 0);
::RGBForeColor(&gAGARamp[rP3]);
::Line(-2, 2);
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(corners[2].h + 1, corners[2].v);
::Line(4, -4);
::RGBForeColor(&gAGARamp[r4]);
::Move(1, 0);
::Line(-5, 5);
break;
case kDTPressedClosed:
if (mEnabled)
::RGBForeColor(&gAGARamp[rP4]);
::MoveTo(corners[0].h + 1, corners[0].v + 2);
::Line(0, 6);
::Move(1, -1);
::Line(0, -4);
::Move(1, 1);
::Line(0, 2);
::Line(1, -1);
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(corners[2].h + 1, corners[2].v);
::Line(4, -4);
::Move(1, 0);
::Line(-5, 5);
break;
case kDTIntermediate:
::RGBForeColor(&gAGARamp[rP4]);
::MoveTo(corners[0].h - 1, corners[0].v + 2);
::Line(-5, 5);
::Move(1, 0);
::Line(4, -4);
::Move(0, 1);
::Line(-3, 3);
::Move(1, 0);
::Line(2, -2);
::Move(0, 1);
::Line(-1, 1);
::Line(1, 0);
break;
case kDTPressedDisclosed:
if (mEnabled)
::RGBForeColor(&gAGARamp[rP4]);
::MoveTo(corners[2].h + 2, corners[2].v + 1);
::Line(6, 0);
::Move(-1, 1);
::Line(-4, 0);
::Move(1, 1);
::Line(2, 0);
::Line(-1, 1);
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(corners[0].h, corners[0].v + 1);
::Line(-4, 4);
::Move(0, 1);
::Line(5, -5);
break;
case kDTDisclosed:
::RGBForeColor(&gAGARamp[rP1]);
::MoveTo(corners[2].h + 2, corners[2].v + 1);
::Line(6, 0);
::RGBForeColor(&gAGARamp[rP2]);
::Line(-1, 1);
::Line(-4, 0);
::Line(1, 1);
::Line(1, 0);
::Move(0, 1);
::RGBForeColor(&gAGARamp[rP3]);
::Line(2, -2);
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(corners[0].h, corners[0].v + 1);
::Line(-4, 4);
::RGBForeColor(&gAGARamp[r4]);
::Move(0, 1);
::Line(5, -5);
break;
}
}
else // 1-bit
{
PolyHandle theTriangle = ::OpenPoly();
::MoveTo(corners[0].h, corners[0].v);
::LineTo(corners[1].h, corners[1].v);
::LineTo(corners[2].h, corners[2].v);
::LineTo(corners[0].h, corners[0].v);
::ClosePoly();
switch (state)
{
case kDTClosed:
case kDTDisclosed:
::RGBForeColor(&gAGARamp[rW]);
::PaintPoly(theTriangle);
::RGBForeColor(&gAGARamp[rB]);
::FramePoly(theTriangle);
if (! mEnabled)
{
::PenPat(&qd.gray);
::PenMode(patBic);
::PaintRect(&mBounds);
::PenNormal();
}
break;
case kDTPressedClosed:
case kDTIntermediate:
case kDTPressedDisclosed:
::RGBForeColor(&gAGARamp[rB]);
::PaintPoly(theTriangle);
break;
}
::KillPoly(theTriangle);
::PenNormal();
}
}
}
void AGADisclosureTriangle::EraseBackground()
{
AGADrawingEnvironment env;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
this->ApplyBackgroundColor();
else
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&mBounds);
}
}
//
// AGAProgressIndicator ---------------------------------------------------------------
//
// This class implements a progress indicator that can be either
// determinate or indeterminate, and also can have a moving start
// value.
//
// We use an offscreen image for the indeterminate progress pattern.
AGAOffscreenImage* AGAProgressIndicator::mgOffscreenIndeterminateProgressImage[kNumProgressPatterns];
// These are the color ramp indexes that are used to build the offscreen image.
SInt8 AGAProgressIndicator::kIndeterminateProgressImage[kNumProgressPatterns]
[kProgressImageHeight]
[kProgressImageWidth] =
{
{ // k1BitPattern
{ rB, rB, rB, rB, rB, rB, rB, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rB, rB, rB, rB, rB, rB, rB, rB, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rB, rB, rB, rB, rB, rB, rB, rB, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rB, rB, rB, rB, rB, rB, rB, rB, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rB, rB, rB, rB, rB, rB, rB, rB, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rB, rB, rB, rB, rB, rB, rB, rB, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rB, rB, rB, rB, rB, rB, rB, rB, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rB, rB, rB, rB, rB, rB, rB, rB, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, rB, rB, rB, rB, rB, rB, rB },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rB, rB, rB, rB, rB, rB, rB },
},
{ // kDeepPattern
{ r11, r11, r11, r11, r11, r11, r11, r11, r10, r10, r10, r10, r10, r10, r10, r10 },
{ r8, r10, r10, r10, r10, r10, r10, r10, r10, r8, r8, r8, r8, r8, r8, r8 },
{ r5, r5, r8, r8, r8, r8, r8, r8, r8, r8, r5, r5, r5, r5, r5, r5 },
{ r2, r2, r2, r5, r5, r5, r5, r5, r5, r5, r5, r2, r2, r2, r2, r2 },
{ rW, rW, rW, rW, r3, r3, r3, r3, r3, r3, r3, r3, rW, rW, rW, rW },
{ r2, r2, r2, r2, r2, r5, r5, r5, r5, r5, r5, r5, r5, r2, r2, r2 },
{ r4, r4, r4, r4, r4, r4, r8, r8, r8, r8, r8, r8, r8, r8, r4, r4 },
{ r6, r6, r6, r6, r6, r6, r6, r10, r10, r10, r10, r10, r10, r10, r10, r6 },
{ r8, r8, r8, r8, r8, r8, r8, r8, r11, r11, r11, r11, r11, r11, r11, r11 },
{ r12, r10, r10, r10, r10, r10, r10, r10, r10, r12, r12, r12, r12, r12, r12, r12 },
},
};
OSErr AGAProgressIndicator::AllocateProgressImages()
{
// Allocate the offscreen image for each radio button state.
OSErr result = noErr;
Point imageSize;
imageSize.h = kProgressImageWidth;
imageSize.v = kProgressImageHeight;
for (UInt32 imageIndex = 0; imageIndex < kNumProgressPatterns; imageIndex++)
{
if (result == noErr)
{
mgOffscreenIndeterminateProgressImage[imageIndex] = new AGAOffscreenImage;
result = mgOffscreenIndeterminateProgressImage[imageIndex]->CreateImageData(
imageSize,
&kIndeterminateProgressImage[imageIndex][0][0],
NULL,
&gAGARamp[rB]);
}
}
return result;
}
void AGAProgressIndicator::DisposeProgressImages()
{
for (UInt32 imageIndex = 0; imageIndex < kNumProgressPatterns; imageIndex++)
if (mgOffscreenIndeterminateProgressImage[imageIndex] != NULL)
delete mgOffscreenIndeterminateProgressImage[imageIndex];
}
AGAProgressIndicator::AGAProgressIndicator(Rect* bounds, SInt32 minimum, SInt32 maximum)
: AGAObject(bounds)
{
// Construct with default options.
// (minimum == maximum) means indeterminate indicator.
mMinimum = minimum;
mMaximum = maximum;
mValue = minimum;
mOriginValue = minimum;
mAnimationIndex = 0;
mLastAnimationTime = 0;
}
AGAProgressIndicator::~AGAProgressIndicator()
{
}
void AGAProgressIndicator::DrawObject()
{
// Draw at current gauge value or next animation step.
this->DrawFrame();
if (mMinimum == mMaximum)
this->DrawAnimationStep();
else
this->DrawGauge();
}
SInt32 AGAProgressIndicator::GetValue()
{
// Return current value.
return mValue;
}
void AGAProgressIndicator::SetValue(SInt32 newValue, Boolean redraw)
{
// Set gauge value, optionally redraw.
// Constrain: mMinimum <= mValue <= mMaximum
newValue = MaxSInt32(mMinimum, MinSInt32(newValue, mMaximum));
if (newValue != mValue)
{
mValue = newValue;
if (redraw)
this->DrawGauge();
}
}
void AGAProgressIndicator::Increment(SInt32 delta, Boolean redraw)
{
// Increment gauge value, optionally redraw.
this->SetValue(delta + this->GetValue(), redraw);
}
void AGAProgressIndicator::Animate()
{
// Draw the next animation step.
mAnimationIndex = (mAnimationIndex + 1) % kNumProgressAnimationSteps;
this->DrawAnimationStep();
}
void AGAProgressIndicator::QuantizedAnimate()
{
// Draw the next animation step if enough time has elapsed since the
// last animation step.
if (mMinimum == mMaximum)
{
SInt32 now = ::TickCount();
if (now > mLastAnimationTime + kAnimationDelay)
{
mLastAnimationTime = now;
this->Animate();
}
}
}
void AGAProgressIndicator::GetRange(SInt32* minimum, SInt32* maximum)
{
// Return the gauge value range.
*minimum = mMinimum;
*maximum = mMaximum;
}
void AGAProgressIndicator::SetRange(SInt32 newMinimum, SInt32 newMaximum, Boolean redraw)
{
// Set the gauge value range, optionally redraw.
// (minimum == maximum) means indeterminate indicator.
if (mOriginValue == mMinimum)
mOriginValue = newMinimum;
mMinimum = newMinimum;
mMaximum = MaxSInt32(newMinimum, newMaximum);
if (redraw)
this->DrawObject();
}
SInt32 AGAProgressIndicator::GetOriginValue()
{
// Return the optional gauge origin value.
return mOriginValue;
}
void AGAProgressIndicator::SetOriginValue(SInt32 newValue, Boolean redraw)
{
// Set the optional gauge origin value.
// Constrain: mMinimum <= mOriginValue <= mValue
newValue = MaxSInt32(mMinimum, MinSInt32(newValue, mValue));
if (newValue != mOriginValue)
{
mOriginValue = newValue;
if (redraw)
this->DrawObject();
}
}
void AGAProgressIndicator::DrawFrame()
{
AGADrawingEnvironment env;
// Draw the constant frame around the indicator.
Rect r = mBounds;
r.bottom = r.top + kProgressHeight;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::LineTo(r.right - 2, r.top);
::RGBForeColor(&gAGARamp[rW]);
::MoveTo(r.left + 1, r.bottom - 1);
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.right - 1, r.top + 1);
}
::InsetRect(&r, 1, 1);
::RGBForeColor(&gAGARamp[rB]);
::FrameRect(&r);
::InsetRect(&r, -1, -1);
}
}
void AGAProgressIndicator::DrawAnimationStep()
{
AGADrawingEnvironment env;
// Draw the indeterminate progress indicator at the
// current animation step.
const UInt32 kNumRows = 10;
Rect r = mBounds;
SInt16 patternHOrigin;
r.bottom = r.top + kProgressHeight;
::InsetRect(&r, 2, 2);
//
// Move the pen leftward so the pattern is offset for
// the current animation step. This will mean we need
// to explicitly clip to our gauge area, since our pattern
// origin is outside it.
//
patternHOrigin = r.left - 32 + ((16 / kNumProgressAnimationSteps) * mAnimationIndex);
RgnHandle savedClip = ::NewRgn();
::GetClip(savedClip);
AGAClipFurther(&r);
r.left = patternHOrigin;
{
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
mgOffscreenIndeterminateProgressImage[kDeepPattern]->DrawPattern(&r);
else
mgOffscreenIndeterminateProgressImage[k1BitPattern]->DrawPattern(&r);
}
} // force GDIterator clip to clean up now, not after we set savedClip!
::SetClip(savedClip);
::DisposeRgn(savedClip);
}
void AGAProgressIndicator::DrawGauge()
{
// Draw the determinate progress indicator.
if (mOriginValue != mMinimum)
this->DrawOriginArea();
this->DrawProgressArea();
this->DrawRemainderArea();
}
void AGAProgressIndicator::DrawOriginArea()
{
// Draw the empty track between the minimum value
// and the origin value.
Rect frame;
if (this->GetOriginFrame(&frame))
{
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = frame;
if (deep)
{
SInt16 width = r.right - r.left;
if (width >= 0)
{
::RGBForeColor(&gAGARamp[rB]);
::MoveTo(r.right, r.top);
::LineTo(r.right, r.bottom - 1);
}
if (width > 0)
{
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.left, r.top);
::LineTo(r.left, r.bottom - 1);
}
if (width > 1)
{
::RGBForeColor(&gAGARamp[r4]);
::MoveTo(r.right - 1, r.top);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r2]);
::LineTo(r.right - 1, r.bottom - 1);
}
if (width > 2)
{
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.left + 1, r.top);
::LineTo(r.left + 1, r.bottom - 1);
}
if (width > 3)
{
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.left + 2, r.bottom - 1);
::LineTo(r.right - 1, r.bottom - 1);
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.left + 2, r.top);
::LineTo(r.right - 2, r.top);
::RGBForeColor(&gAGARamp[r4]);
r.left += 2;
r.top++;
r.bottom--;
r.right--;
::PaintRect(&r);
}
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
}
}
}
}
void AGAProgressIndicator::DrawProgressArea()
{
AGADrawingEnvironment env;
// Draw the filled progress gauge area between
// the origin and the current value.
Rect frame;
if (this->GetProgressFrame(&frame))
{
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = frame;
if (deep)
{
SInt16 width = r.right - r.left;
//
// Because the endcaps of the gauge are shaded,
// we need to carefully draw the ends horizontal
// pixel by pixel, bailing out if there is not
// enough width to accomodate the endcaps and the
// midsection.
//
if (width > 0)
{
::RGBForeColor(&gAGARamp[rB]);
::MoveTo(r.right - 1, r.top);
::LineTo(r.right - 1, r.bottom - 1);
}
if (width > 1)
{
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left, r.top);
::LineTo(r.left, r.bottom - 1);
}
if (width > 2)
{
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.right - 2, r.top);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r12]);
::LineTo(r.right - 2, r.bottom - 1);
}
if (width > 3)
{
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left + 1, r.top);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r3]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r1]);
::Line(0, 3);
::RGBForeColor(&gAGARamp[r3]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r10]);
::Line(0, 0);
}
if (width > 4)
{
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.right - 3, r.top);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r10]);
::LineTo(r.right - 3, r.bottom - 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
}
if (width > 5)
{
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.right - 4, r.top);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r5]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r3]);
::Line(0, 3);
::RGBForeColor(&gAGARamp[r5]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r8]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r10]);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r12]);
::Line(0, 0);
}
if (width > 6)
{
SInt16 distance = width - 7;
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.left + 2, r.top);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left + 2, r.top + 1);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(r.left + 2, r.top + 2);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r3]);
::MoveTo(r.left + 2, r.top + 3);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r1]);
::MoveTo(r.left + 2, r.top + 4);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r3]);
::MoveTo(r.left + 2, r.top + 5);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r5]);
::MoveTo(r.left + 2, r.top + 6);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r8]);
::MoveTo(r.left + 2, r.top + 7);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.left + 2, r.top + 8);
::Line(distance, 0);
::RGBForeColor(&gAGARamp[r12]);
::MoveTo(r.left + 2, r.top + 9);
::Line(distance, 0);
}
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rB]);
::PaintRect(&r);
}
}
}
}
void AGAProgressIndicator::DrawRemainderArea()
{
AGADrawingEnvironment env;
// Draw the empty track area between the current
// gauge value and the maximum.
Rect frame;
if (this->GetRemainderFrame(&frame))
{
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = frame;
if (deep)
{
SInt16 width = r.right - r.left;
if (width > 0)
{
::RGBForeColor(&gAGARamp[r10]);
::MoveTo(r.left, r.top);
::LineTo(r.left, r.bottom - 1);
}
if (width > 1)
{
::RGBForeColor(&gAGARamp[r4]);
::MoveTo(r.right - 1, r.top);
::Line(0, 1);
::RGBForeColor(&gAGARamp[r2]);
::LineTo(r.right - 1, r.bottom - 1);
}
if (width > 2)
{
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.left + 1, r.top);
::LineTo(r.left + 1, r.bottom - 1);
}
if (width > 3)
{
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.left + 2, r.bottom - 1);
::LineTo(r.right - 1, r.bottom - 1);
::RGBForeColor(&gAGARamp[r7]);
::MoveTo(r.left + 2, r.top);
::LineTo(r.right - 2, r.top);
::RGBForeColor(&gAGARamp[r4]);
r.left += 2;
r.top++;
r.bottom--;
r.right--;
::PaintRect(&r);
}
}
else // 1-bit
{
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
}
}
}
}
Boolean AGAProgressIndicator::GetOriginFrame(Rect* originFrame)
{
// Return true (and the area) if there is an area
// to be drawn for the empty origin part of the track.
Boolean isNeeded = false;
if (mOriginValue != mMinimum)
{
isNeeded = true;
this->GetRangeFrame(mMinimum, mOriginValue, originFrame);
if (mOriginValue != mMaximum)
originFrame->right--;
}
return isNeeded;
}
Boolean AGAProgressIndicator::GetProgressFrame(Rect* progressFrame)
{
// Return true (and the area) if there is an area
// to be drawn for the progress section of the gauge.
Boolean isNeeded = false;
if (mValue != mOriginValue)
{
isNeeded = true;
this->GetRangeFrame(mOriginValue, mValue, progressFrame);
if (mValue == mMaximum)
progressFrame->right++;
}
return isNeeded;
}
Boolean AGAProgressIndicator::GetRemainderFrame(Rect* remainderFrame)
{
// Return true (and the area) if there is an area
// to be drawn for the uncompleted gauge remainder area.
Boolean isNeeded = false;
if (mMaximum != mValue)
{
isNeeded = true;
this->GetRangeFrame(mValue, mMaximum, remainderFrame);
}
return isNeeded;
}
void AGAProgressIndicator::GetRangeFrame(SInt32 startValue, SInt32 endValue, Rect* rangeFrame)
{
// Return the rectangle that the indicator draws in,
// which does not include the constant border frame area.
*rangeFrame = mBounds;
rangeFrame->bottom = rangeFrame->top + kProgressHeight;
::InsetRect(rangeFrame, 2, 2);
SInt32 divisor = mMaximum - mMinimum;
if (divisor != 0) // avoid divide by zero
{
SInt32 totalWidth = rangeFrame->right - rangeFrame->left;
float startFraction = ((float) (startValue - mMinimum)) / divisor;
float endFraction = ((float) (endValue - mMinimum)) / divisor;
rangeFrame->right = rangeFrame->left + (endFraction * totalWidth);
rangeFrame->left = rangeFrame->left + (startFraction * totalWidth);
}
}
//
// AGASeparator ---------------------------------------------------------------
//
// This class draws a separator line. It knowns whether it's horizontal or
// vertical based on the larger dimension.
//
AGASeparator::AGASeparator(Rect* bounds)
: AGAObject(bounds)
{
// Call superclass constructor.
}
AGASeparator::~AGASeparator()
{
}
void AGASeparator::DrawObject()
{
AGADrawingEnvironment env;
// Draw the separator along the leading edge in
// its longest dimension.
Boolean isHorizontal = ((mBounds.right - mBounds.left) > (mBounds.bottom - mBounds.top));
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
::RGBForeColor(&gAGARamp[r7]);
else
{
::RGBForeColor(&gAGARamp[rB]);
::PenPat(&qd.gray);
}
::MoveTo(mBounds.left, mBounds.top);
if (isHorizontal)
::LineTo(mBounds.right - 2, mBounds.top);
else
::LineTo(mBounds.left, mBounds.bottom - 2);
if (deep)
{
::RGBForeColor(&gAGARamp[rW]);
::MoveTo(mBounds.left + 1, mBounds.top + 1);
if (isHorizontal)
::LineTo(mBounds.right - 1, mBounds.top + 1);
else
::LineTo(mBounds.left + 1, mBounds.bottom - 1);
}
else
::PenPat(&qd.black);
}
}
//
// AGAGroupBox ---------------------------------------------------------------
//
// This class draws primary and secondary group boxes, with optional
// title label or title gap for a separate control.
//
AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType)
: AGAObject(bounds)
{
// Construct without a title or gap.
mIsPrimaryBox = groupBoxType;
mTitleGap = 0;
mTitle[0] = 0;
mTextStyle = textStyle;
}
AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType, SInt16 titleGap)
: AGAObject(bounds)
{
// Construct with specified gap.
mIsPrimaryBox = groupBoxType;
mTitleGap = titleGap;
mTitle[0] = 0;
mTextStyle = textStyle;
}
AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType, StringPtr titleString)
: AGAObject(bounds)
{
// Construct with specified title.
mIsPrimaryBox = groupBoxType;
mTitleGap = 0;
AGA_PLstrcpy(mTitle, titleString);
mTextStyle = textStyle;
}
AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType, SInt16 titleStringListResourceID, SInt16 titleStringIndex)
: AGAObject(bounds)
{
// Construct by getting title from specified resource.
mIsPrimaryBox = groupBoxType;
mTitleGap = 0;
::GetIndString(mTitle, titleStringListResourceID, titleStringIndex);
mTextStyle = textStyle;
}
AGAGroupBox::~AGAGroupBox()
{
}
void AGAGroupBox::SetTitleGap(SInt16 titleGap)
{
// Set the width of the title gap that will be left blank.
mTitleGap = titleGap;
}
void AGAGroupBox::SetTitle(StringPtr newTitle, Boolean redraw)
{
// Set the title, optionally redraw.
AGA_PLstrcpy(mTitle, newTitle);
if (redraw)
this->DrawObject();
}
void AGAGroupBox::DrawObject()
{
AGADrawingEnvironment env;
// Draw the group box.
Rect r = mBounds;
SInt16 titleGap = 0;
SInt16 topIndent = 0;
FontInfo fontInfo;
if (mTitle[0] != 0)
{
mTextStyle.PrepareForDrawing(); // calculate gap for title's text style
::GetFontInfo(&fontInfo);
topIndent = fontInfo.ascent; // text baseline should be at frame top
titleGap = 5 + ::StringWidth(mTitle);
}
else
titleGap = mTitleGap;
if (mIsPrimaryBox)
this->DrawPrimaryFrame(topIndent, titleGap);
else
this->DrawSecondaryFrame(topIndent, titleGap);
if (mTitle[0] != 0)
{
Rect titleRect;
titleRect.left = r.left + 14;
titleRect.top = r.top + 2;
titleRect.right = titleRect.left + titleGap;
titleRect.bottom = titleRect.top + fontInfo.ascent + fontInfo.descent;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
AGAStringOut(mTitle, &titleRect, kNoTruncation, teFlushDefault, mEnabled ? kNormalOutput : kDisabledOutput, deep, mTextStyle);
}
}
void AGAGroupBox::DrawPrimaryFrame(SInt16 topIndent, SInt16 gapSize)
{
// Draw the group box as a primary group.
Rect r = mBounds;
r.top += topIndent;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
if (mEnabled)
::RGBForeColor(&gAGARamp[r7]);
else
::RGBForeColor(&gAGARamp[r4]);
}
else
{
::RGBForeColor(&gAGARamp[rB]);
if (! mEnabled)
::PenPat(&qd.gray);
}
::MoveTo(r.right - 2, r.top);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::Line(10, 0);
::Move(gapSize, 0);
::LineTo(r.right - 2, r.top);
if (deep)
{
if (mEnabled)
::RGBForeColor(&gAGARamp[rW]);
else
this->ApplyBackgroundColor();
::MoveTo(r.right - 1, r.top);
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.left, r.bottom - 1);
::MoveTo(r.left + 1, r.bottom - 3);
::LineTo(r.left + 1, r.top + 1);
::Line(9, 0);
::Move(gapSize, 0);
::LineTo(r.right - 3, r.top + 1);
}
else
::PenPat(&qd.black);
}
}
void AGAGroupBox::DrawSecondaryFrame(SInt16 topIndent, SInt16 gapSize)
{
// Draw the group box as a secondary group.
Rect r = mBounds;
r.top += topIndent;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
::MoveTo(r.right - 1, r.top);
if (mEnabled)
{
::RGBForeColor(&gAGARamp[rW]);
::Move(0, 1);
}
else
::RGBForeColor(&gAGARamp[r4]);
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.left + 1, r.bottom - 1);
if (mEnabled)
{
::Move(-1, -1);
::RGBForeColor(&gAGARamp[r7]);
}
else
::Line(-1, 0);
::LineTo(r.left, r.top);
::Line(10, 0);
::Move(gapSize, 0);
::LineTo(r.right - 2, r.top);
}
else
{
::RGBForeColor(&gAGARamp[rB]);
if (! mEnabled)
::PenPat(&qd.gray);
::MoveTo(r.right - 2, r.top);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::Line(10, 0);
::Move(gapSize, 0);
::LineTo(r.right - 2, r.top);
if (! mEnabled)
::PenPat(&qd.black);
}
}
}
//
// AGATabPanel ---------------------------------------------------------------
//
// AGATabPanel implements a folder tabs box, often referred to as a "tabbed
// dialog" interface.
//
AGATabPanel::AGATabPanel(Rect* bounds, SInt32 initialTabIndex, const AGATextStyle& textStyle, SInt16 labelsID)
: AGAObject(bounds)
{
// Construct with default options.
mNumTabs = 0;
mCurrentTabIndex = initialTabIndex;
mTabInfo = NULL;
mTabsLocation = kTopTabs;
mTabWidthKind = kVariableTabWidth;
mDrawFrame = true;
mTextStyle = textStyle;
mTabSize = ((textStyle.mFontSize > 10) || (textStyle.mFontSize == 0)) ? kLargeTabs : kSmallTabs;
this->CalculateTabSizeInfo();
this->SetLabelsFromResource(labelsID);
}
AGATabPanel::AGATabPanel(Rect* bounds, SInt32 initialTabIndex, const AGATextStyle& textStyle, SInt16 labelsID, TabWidthKind widthKind, TabsLocation location, Boolean drawFrame)
: AGAObject(bounds)
{
// Construct with specified options.
mNumTabs = 0;
mCurrentTabIndex = initialTabIndex;
mTabInfo = NULL;
mTabsLocation = location;
mTabWidthKind = widthKind;
mDrawFrame = drawFrame;
mTextStyle = textStyle;
mTabSize = ((textStyle.mFontSize > 10) || (textStyle.mFontSize == 0)) ? kLargeTabs : kSmallTabs;
this->CalculateTabSizeInfo();
this->SetLabelsFromResource(labelsID);
}
AGATabPanel::~AGATabPanel()
{
// Destruct by releasing memory allocated for labels.
this->DisposeTabInfo();
}
void AGATabPanel::DrawObject()
{
this->DrawBackground();
this->DrawFrame();
this->DrawTabs();
}
Boolean AGATabPanel::TrackMouse(Point mouseLocation)
{
Boolean wasItHit;
Rect tabRect;
//
// First we determine which tab, if any, was clicked.
//
mLastTabClicked = -1;
for (SInt32 i = 0; i < mNumTabs; i++)
{
this->GetTabBounds(i, &tabRect);
if (::PtInRect(mouseLocation, &tabRect) && this->IsTabEnabled(i))
{
mLastTabClicked = i;
break;
}
}
//
// Now we let the standard in/out tracking occur.
// Our hit test will compare with the mLastTabClicked
// area.
//
wasItHit = AGAObject::TrackMouse(mouseLocation);
if (! wasItHit)
mLastTabClicked = -1;
return wasItHit;
}
void AGATabPanel::SetObjectBounds(Rect* bounds, Boolean redraw)
{
AGAObject::SetObjectBounds(bounds, redraw);
this->CalculateTabWidths();
this->CalculateTabSizeInfo();
}
Boolean AGATabPanel::HitTest(Point mouseLocation)
{
Boolean isIn;
// Return true if the mouse is in the mLastTabClicked.
if (mLastTabClicked == -1)
isIn = false;
else
{
Rect tabRect;
this->GetTabBounds(mLastTabClicked, &tabRect);
isIn = ::PtInRect(mouseLocation, &tabRect);
}
return isIn;
}
void AGATabPanel::SetTrackingState(Boolean isIn)
{
// Draw the mLastTabClicked pressed or unpressed as specified.
if ((mLastTabClicked != -1) && (mLastTabClicked != mCurrentTabIndex))
this->DrawOneTab(mLastTabClicked, isIn);
}
SInt32 AGATabPanel::GetCurrentTab()
{
return mCurrentTabIndex;
}
void AGATabPanel::SetCurrentTab(SInt32 tabIndex, Boolean redraw)
{
if (tabIndex != mCurrentTabIndex)
{
mCurrentTabIndex = tabIndex;
if (redraw)
this->DrawTabs();
}
}
SInt32 AGATabPanel::GetLastTabClicked()
{
return mLastTabClicked;
}
void AGATabPanel::SetTabSize(TabSize size)
{
// Set the tabs size.
mTabSize = size;
this->CalculateTabSizeInfo();
}
void AGATabPanel::SetTabsLocation(TabsLocation location)
{
// Set the tabs location.
mTabsLocation = location;
this->CalculateTabSizeInfo();
}
void AGATabPanel::SetTabsWidth(TabWidthKind widthKind)
{
// Set the tabs width style.
mTabWidthKind = widthKind;
this->CalculateTabWidths();
}
SInt16 AGATabPanel::GetTabHeight()
{
// Return the current tab image height (or width if oriented vertically).
if ((mTabsLocation == kTopTabs) || (mTabsLocation == kBottomTabs))
return mTabImageSize.v;
else
return mTabImageSize.h;
}
Boolean AGATabPanel::HasFrame()
{
return mDrawFrame;
}
void AGATabPanel::SetLabelsFromResource(SInt16 stringListResourceID)
{
// Build the tab labels from the specified 'STR#' resource.
// A label slot is allocated for each string in the resource;
// there will be a tab for each of these strings.
this->DisposeTabInfo();
if (stringListResourceID != 0)
{
SInt16** stringListHandle = (SInt16**) ::GetResource('STR#', stringListResourceID);
SInt32 numTabs = (stringListHandle == NULL) ? 0 : **stringListHandle;
if (numTabs != 0)
{
this->AllocateTabInfo(numTabs, kShrinkToFit);
for (SInt16 i = 0; i < mNumTabs; i++)
{
Str255 aLabel;
::GetIndString(aLabel, stringListResourceID, i+1);
this->SetTabLabel(i, aLabel);
}
this->CalculateTabWidths();
}
}
}
void AGATabPanel::SetNumTabs(SInt32 numTabs, Boolean shrinkToFit)
{
// Allocate slots for the specified number of labels.
this->AllocateTabInfo(numTabs, shrinkToFit);
// In case the caller never informs us when the labels have
// all been set (i.e., never calls CalculateTabWidths), we
// init the widths to fill the bounds.
this->CalculateTabWidthsByKind(kVariableTabWidth);
}
SInt32 AGATabPanel::GetNumTabs()
{
return mNumTabs;
}
void AGATabPanel::AllocateTabInfo(SInt32 numTabs, Boolean shrinkToFit)
{
// Make sure the tab info handle is sized to fit the
// specified number of tabs.
if (mTabInfo == NULL)
{
mTabInfo = (TabInfoHandle) ::NewHandleClear(numTabs * sizeof(TabInfo));
if (mTabInfo == NULL)
mNumTabs = 0;
else
mNumTabs = numTabs;
}
else if ((mNumTabs < numTabs) || (shrinkToFit && (mNumTabs > numTabs)))
{
::SetHandleSize((Handle) mTabInfo, numTabs * sizeof(TabInfo));
if (::MemError() != noErr)
return;
// Make sure the new tab info elements are zeroed like NewHandleClear.
for (SInt32 i = mNumTabs; i < numTabs; i++)
{
(*mTabInfo)[i].mLabel = NULL;
(*mTabInfo)[i].mTabWidth = 0;
(*mTabInfo)[i].mDisabled = false;
(*mTabInfo)[i].mUserData = NULL;
}
mNumTabs = numTabs;
}
}
void AGATabPanel::SetTabLabel(SInt32 tabIndex, StringPtr itsLabel)
{
// Assign the specified string to the specified label slot.
if (mTabInfo != NULL)
{
if (tabIndex < mNumTabs)
(*mTabInfo)[tabIndex].mLabel = ::NewString(itsLabel);
}
}
void AGATabPanel::GetTabLabel(SInt32 tabIndex, StringPtr itsLabel)
{
// Return the label string of the specified label slot.
itsLabel[0] = 0;
if (mTabInfo != NULL)
{
if (tabIndex < mNumTabs)
{
StringHandle labelStringHandle = (*mTabInfo)[tabIndex].mLabel;
if (labelStringHandle != NULL)
{
Ptr sourceStringPtr = (Ptr) *((*mTabInfo)[tabIndex].mLabel);
::BlockMoveData(sourceStringPtr, itsLabel, 1 + *sourceStringPtr);
}
}
}
}
void AGATabPanel::SetTabEnable(SInt32 tabIndex, Boolean enable)
{
// Enable or disable the specified tab.
if (mTabInfo != NULL)
{
if (tabIndex < mNumTabs)
(*mTabInfo)[tabIndex].mDisabled = ! enable;
}
}
Boolean AGATabPanel::IsTabEnabled(SInt32 tabIndex)
{
// Return the enable state of the specified tab.
Boolean isEnabled = true;
if (mTabInfo != NULL)
{
if (tabIndex < mNumTabs)
isEnabled = ! (*mTabInfo)[tabIndex].mDisabled;
}
return isEnabled;
}
void AGATabPanel::SetTabUserData(SInt32 tabIndex, void* userData)
{
// Stash the userData in the specified tab's info.
if (mTabInfo != NULL)
{
if (tabIndex < mNumTabs)
(*mTabInfo)[tabIndex].mUserData = userData;
}
}
void* AGATabPanel::GetTabUserData(SInt32 tabIndex)
{
// Return the specified tab's mUserData.
void* userData = NULL;
if (mTabInfo != NULL)
{
if (tabIndex < mNumTabs)
userData = (*mTabInfo)[tabIndex].mUserData;
}
return userData;
}
void AGATabPanel::SetLabelsStyle(const AGATextStyle& textStyle)
{
// Set the QuickDraw text style for the labels.
mTextStyle = textStyle;
this->CalculateTabWidths();
this->CalculateTabSizeInfo();
}
void AGATabPanel::CalculateTabWidths()
{
this->CalculateTabWidthsByKind(mTabWidthKind);
}
void AGATabPanel::CalculateTabWidthsByKind(TabWidthKind widthKind)
{
SInt32 widthAvailable;
Str255 aLabel;
SInt32 tabWidth;
SInt32 totalWidth;
SInt32 overflow;
SInt32 tabEndWidth;
if ((mTabsLocation == kTopTabs) || (mTabsLocation == kBottomTabs))
{
widthAvailable = mBounds.right - mBounds.left - (2 * kPanelEndMargin);
tabEndWidth = mTabImageSize.h;
}
else
{
widthAvailable = mBounds.bottom - mBounds.top - (2 * kPanelEndMargin);
tabEndWidth = mTabImageSize.v;
}
mTextStyle.PrepareForDrawing();
switch (widthKind)
{
case kVariableTabWidth:
totalWidth = 0;
for (SInt32 i = 0; i < mNumTabs; i++)
{
this->GetTabLabel(i, aLabel);
tabWidth = ::StringWidth(aLabel) + (2 * tabEndWidth);
totalWidth += tabWidth;
(*mTabInfo)[i].mTabWidth = tabWidth;
}
// If we overflowed the available width, reduce the tab sizes.
overflow = totalWidth - widthAvailable;
if (overflow > 0)
for (SInt32 i = 0; i < mNumTabs; i++)
(*mTabInfo)[i].mTabWidth -= (1 + (overflow / mNumTabs));
break;
case kCommonTabWidth:
tabWidth = 0;
for (SInt32 i = 0; i < mNumTabs; i++)
{
this->GetTabLabel(i, aLabel);
tabWidth = MaxSInt32(tabWidth, ::StringWidth(aLabel));
}
tabWidth += (2 * tabEndWidth);
for (SInt32 i = 0; i < mNumTabs; i++)
(*mTabInfo)[i].mTabWidth = tabWidth;
// If we overflowed the available width, reduce the tab sizes.
overflow = (tabWidth * mNumTabs) - widthAvailable;
if (overflow > 0)
for (SInt32 i = 0; i < mNumTabs; i++)
(*mTabInfo)[i].mTabWidth -= (1 + (overflow / mNumTabs));
break;
}
}
void AGATabPanel::DrawBackground()
{
AGADrawingEnvironment env;
// Paint the background.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
this->ApplyBackgroundColor();
else
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&mBounds);
}
}
void AGATabPanel::DrawFrame()
{
// If we have a frame, draw it; otherwise, draw the line/shading
// for just the tabs edge.
if (mDrawFrame)
this->DrawFrameBox();
else
this->DrawFrameTop();
}
void AGATabPanel::DrawFrameTop()
{
// Draw the line and shading for the tabs without a frame.
AGADrawingEnvironment env;
Rect frameBounds = mBounds;
frameBounds.top = frameBounds.bottom - 3;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = frameBounds;
if (deep && !mEnabled)
::RGBForeColor(&gAGARamp[r10]);
else
::RGBForeColor(&gAGARamp[rB]);
::MoveTo(r.left, r.top);
::LineTo(r.right - 1, r.top);
if (deep)
{
if (mEnabled)
::RGBForeColor(&gAGARamp[r3]);
else
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.left + 1, r.top + 1);
::LineTo(r.right - 2, r.top + 1);
if (mEnabled)
::RGBForeColor(&gAGARamp[rW]);
else
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.left + 2, r.top + 2);
::LineTo(r.right - 3, r.top + 2);
}
}
}
void AGATabPanel::DrawFrameBox()
{
// Draw the tab panel frame box.
AGADrawingEnvironment env;
enum { Frame, Fill, LightOuter, LightInner, DarkOuter, DarkInner, kNumFrameColors };
UInt8 colorIndexes[kNumFrameColors];
Rect frameBounds = mBounds;
if (mEnabled)
{
colorIndexes[Frame] = rB;
colorIndexes[Fill] = r1;
colorIndexes[LightOuter] = r3;
colorIndexes[LightInner] = rW;
colorIndexes[DarkOuter] = r6;
colorIndexes[DarkInner] = r4;
}
else
{
colorIndexes[Frame] = r10;
colorIndexes[Fill] = r2;
colorIndexes[LightOuter] = r2;
colorIndexes[LightInner] = r2;
colorIndexes[DarkOuter] = r2;
colorIndexes[DarkInner] = r2;
}
frameBounds.top += (mTabImageSize.v - 3);
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = frameBounds;
if (deep)
::RGBForeColor(&gAGARamp[colorIndexes[Frame]]);
else
{
::RGBForeColor(&gAGARamp[rB]);
if (! mEnabled)
::PenPat(&qd.gray);
}
::FrameRect(&r);
if (deep)
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
else
{
::RGBForeColor(&gAGARamp[rW]);
if (! mEnabled) // put it back if we set to gray above
::PenPat(&qd.black);
}
::InsetRect(&r, 1, 1);
::PaintRect(&r);
if (deep && mEnabled) // disabled has no raised light/dark edges
{
::RGBForeColor(&gAGARamp[colorIndexes[LightOuter]]);
::MoveTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::LineTo(r.right - 2, r.top);
::RGBForeColor(&gAGARamp[colorIndexes[DarkOuter]]);
::Move(1, 1);
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.left + 1, r.bottom - 1);
::RGBForeColor(&gAGARamp[colorIndexes[LightInner]]);
::Move(0, -2);
::LineTo(r.left + 1, r.top + 1);
::LineTo(r.right - 3, r.top + 1);
::RGBForeColor(&gAGARamp[colorIndexes[DarkInner]]);
::Move(1, 1);
::LineTo(r.right - 2, r.bottom - 2);
::LineTo(r.left + 2, r.bottom - 2);
::RGBForeColor(&gAGARamp[r2]);
::MoveTo(r.left, r.bottom - 1);
::Line(0, 0);
::MoveTo(r.top, r.right - 1);
::Line(0, 0);
}
}
}
void AGATabPanel::DrawTabs()
{
// Draw the tabs, one at a time.
for (SInt32 i = 0; i < mNumTabs; i++)
this->DrawOneTab(i, kNotPressed);
}
void AGATabPanel::DrawOneTab(SInt32 tabIndex, Boolean pressed)
{
// Draw the specified tab.
AGADrawingEnvironment env;
enum { EdgeFrame, OuterEdge, InnerEdge, Fill, InteriorFrame, InteriorOuterEdge, InteriorInnerEdge, kNumTabColors };
UInt8 colorIndexes[kNumTabColors];
Boolean selected = (tabIndex == mCurrentTabIndex);
Rect tabBounds;
Str255 tabLabel;
Point tabOrigin;
AGAStringOutColor textColor;
UInt32 leftImageIndex;
UInt32 rightImageIndex;
this->GetTabBounds(tabIndex, &tabBounds);
this->GetTabLabel(tabIndex, tabLabel);
tabBounds.left += mTabImageSize.h;
tabBounds.right -= mTabImageSize.h;
if ((! mEnabled) || ! this->IsTabEnabled(tabIndex))
{
textColor = kDisabledOutput;
leftImageIndex = selected ? kTabDisabledSelectedL : kTabDisabledDeselectedL;
rightImageIndex = selected ? kTabDisabledSelectedR : kTabDisabledDeselectedR;
colorIndexes[EdgeFrame] = r10;
colorIndexes[OuterEdge] = r2;
colorIndexes[InnerEdge] = r2;
colorIndexes[Fill] = r2;
colorIndexes[InteriorFrame] = selected ? r2 : r10;
colorIndexes[InteriorOuterEdge] = r2;
colorIndexes[InteriorInnerEdge] = r2;
}
else if (pressed)
{
textColor = kInverseOutput;
leftImageIndex = kTabPressedL;
rightImageIndex = kTabPressedR;
colorIndexes[EdgeFrame] = rB;
colorIndexes[OuterEdge] = r11;
colorIndexes[InnerEdge] = r10;
colorIndexes[Fill] = r9;
colorIndexes[InteriorFrame] = rB;
colorIndexes[InteriorOuterEdge] = r3;
colorIndexes[InteriorInnerEdge] = rW;
}
else if (selected)
{
textColor = kNormalOutput;
leftImageIndex = kTabNormalSelectedL;
rightImageIndex = kTabNormalSelectedR;
colorIndexes[EdgeFrame] = rB;
colorIndexes[OuterEdge] = r3;
colorIndexes[InnerEdge] = rW;
colorIndexes[Fill] = r1;
colorIndexes[InteriorFrame] = r1;
colorIndexes[InteriorOuterEdge] = r1;
colorIndexes[InteriorInnerEdge] = r1;
}
else
{
textColor = kNormalOutput;
leftImageIndex = kTabNormalDeselectedL;
rightImageIndex = kTabNormalDeselectedR;
colorIndexes[EdgeFrame] = rB;
colorIndexes[OuterEdge] = r3;
colorIndexes[InnerEdge] = r2;
colorIndexes[Fill] = r3;
colorIndexes[InteriorFrame] = rB;
colorIndexes[InteriorOuterEdge] = r3;
colorIndexes[InteriorInnerEdge] = rW;
}
// Note that at this point, tabBounds is inset to avoid
// the corner images.
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
// Draw the tab corner images.
tabOrigin.h = tabBounds.left - mTabImageSize.h;
tabOrigin.v = tabBounds.top;
this->CopyTabImage(leftImageIndex, tabOrigin, deep);
tabOrigin.h = tabBounds.right;
this->CopyTabImage(rightImageIndex, tabOrigin, deep);
// Draw the straight edge shading.
Rect r = tabBounds;
::RGBForeColor(&gAGARamp[colorIndexes[EdgeFrame]]);
::MoveTo(r.left, r.top);
::LineTo(r.right - 1, r.top);
if (deep)
{
r.top++;
r.bottom--;
::RGBForeColor(&gAGARamp[colorIndexes[OuterEdge]]);
::MoveTo(r.left, r.top);
::LineTo(r.right - 1, r.top);
r.top++;
::RGBForeColor(&gAGARamp[colorIndexes[InnerEdge]]);
::MoveTo(r.left, r.top);
::LineTo(r.right - 1, r.top);
r.top++;
::RGBForeColor(&gAGARamp[colorIndexes[InteriorInnerEdge]]);
::MoveTo(r.left, r.bottom);
::LineTo(r.right - 1, r.bottom);
r.bottom--;
::RGBForeColor(&gAGARamp[colorIndexes[InteriorOuterEdge]]);
::MoveTo(r.left, r.bottom);
::LineTo(r.right - 1, r.bottom);
r.bottom--;
::RGBForeColor(&gAGARamp[colorIndexes[InteriorFrame]]);
::MoveTo(r.left, r.bottom);
::LineTo(r.right - 1, r.bottom);
::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
::PaintRect(&r);
}
else
{
// For 1-bit drawing, there's a pixel at the bottom that
// may need to be erased or re-drawn. It's either leftover
// from the frame (need to erase), or missing from being
// previously selected (need to draw).
r.bottom -= 3;
r.top++;
if (selected)
::RGBForeColor(&gAGARamp[rW]);
else
::RGBForeColor(&gAGARamp[rB]);
::MoveTo(r.left, r.bottom);
::LineTo(r.right - 1, r.bottom);
// The enable state of the tabs as a whole, and this
// tab in particular require us to paint a gray pattern over
// some or all of the tab corner images.
if ((! mEnabled) || ! this->IsTabEnabled(tabIndex))
{
Rect rectToPaint = tabBounds;
rectToPaint.left -= mTabImageSize.h;
rectToPaint.right += mTabImageSize.h;
// If whole thing is enabled but this tab is disabled,
// make sure we don't gray out the box frame line segment.
if (mEnabled && ! this->IsTabEnabled(tabIndex))
rectToPaint.bottom -= 3;
::PenPat(&qd.gray);
::PenMode(patBic);
::PaintRect(&rectToPaint);
::PenNormal();
}
// We also need to paint the tab rectangular inside area
// black or white, depending on whether the tab is pressed,
// in preparation for the label text.
if (pressed)
::RGBForeColor(&gAGARamp[rB]);
else
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&r);
}
AGAStringOut(tabLabel, &tabBounds, smTruncMiddle, teCenter, textColor, deep, mTextStyle);
}
}
void AGATabPanel::GetTabBounds(SInt32 tabIndex, Rect* tabBounds)
{
// Return the bounds of the specified tab.
SInt16 tabOrigin = kPanelEndMargin;
SInt16 tabWidth = (*mTabInfo)[tabIndex].mTabWidth;
for (SInt32 i = 0; i < tabIndex; i++)
tabOrigin += (*mTabInfo)[i].mTabWidth;;
switch (mTabsLocation)
{
case kTopTabs:
case kBottomTabs:
tabBounds->left = mBounds.left + tabOrigin;
tabBounds->right = tabBounds->left + tabWidth;
if ((mDrawFrame && (mTabsLocation == kTopTabs)) ||
(!mDrawFrame && (mTabsLocation == kBottomTabs)))
{
tabBounds->top = mBounds.top;
tabBounds->bottom = mBounds.top + mTabImageSize.v;
}
else
{
tabBounds->top = mBounds.bottom - mTabImageSize.v;
tabBounds->bottom = mBounds.bottom;
}
break;
case kLeftTabs:
case kRightTabs:
tabBounds->top = mBounds.top + tabOrigin;
tabBounds->bottom = tabBounds->top + tabWidth;
if ((mDrawFrame && (mTabsLocation == kLeftTabs)) ||
(!mDrawFrame && (mTabsLocation == kRightTabs)))
{
tabBounds->left = mBounds.left;
tabBounds->right = mBounds.left + mTabImageSize.h;
}
else
{
tabBounds->left = mBounds.right - mTabImageSize.h;
tabBounds->right = mBounds.right;
}
break;
}
}
void AGATabPanel::CalculateTabSizeInfo()
{
// Recalculate the tab image size based on the tab size kind and
// the tab location orientation.
// Decide whether our bounds are large enough to draw a frame.
switch (mTabSize)
{
case kSmallTabs:
switch (mTabsLocation)
{
case kTopTabs:
case kBottomTabs:
::SetPt(&mTabImageSize, kSmallTabImageWidth, kSmallTabImageHeight);
break;
case kLeftTabs:
case kRightTabs:
::SetPt(&mTabImageSize, kSmallTabImageHeight, kSmallTabImageWidth);
break;
}
break;
case kLargeTabs:
switch (mTabsLocation)
{
case kTopTabs:
case kBottomTabs:
::SetPt(&mTabImageSize, kLargeTabImageWidth, kLargeTabImageHeight);
break;
case kLeftTabs:
case kRightTabs:
::SetPt(&mTabImageSize, kLargeTabImageHeight, kLargeTabImageWidth);
break;
}
break;
}
//
// If the bounds are small, we don't draw the frame. We allow some
// leeway in layout so that the user doesn't have to make the bounds
// exactly match the image size to suppress the frame. This is fine
// because if there is a frame, it won't be that small.
//
mDrawFrame = ((mBounds.bottom - mBounds.top) > (mTabImageSize.v + 16));
}
void AGATabPanel::DisposeTabInfo()
{
// Release the memory allocated for slider labels.
if (mTabInfo != NULL)
{
for (SInt32 i = 0; i < mNumTabs; i++)
::DisposeHandle((Handle) (*mTabInfo)[i].mLabel);
::DisposeHandle((Handle) mTabInfo);
mTabInfo = NULL;
}
mNumTabs = 0;
}
// Each radio button drawing state has an offscreen image.
AGAOffscreenImage* AGATabPanel::mgOffscreenTabImages [kNumTabImages] [kNumImageTypes];
AGAOffscreenImage* AGATabPanel::mg1BitOffscreenTabImages [kNumTabImages] [kNumImageTypes];
// These are the color ramp indexes that are used to build the small tab offscreen images.
SInt8 AGATabPanel::kSmallTabImageValues [kNumTabImages] [kSmallTabImageHeight] [kSmallTabImageWidth] =
{
{ // kTabNormalDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB, r5, r3 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, r5, r3, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r12, r5, r2, r2, r3, r3 },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, OUT, r12, r3, r2, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3 },
// { OUT, OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, r12, r5, r2, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3 },
// { OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, r12, r5, r2, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3 },
// { OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, r12, r5, r2, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3 },
// { OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, r12, r5, r2, r3, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3, r3 },
// { OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3, r3 },
{ r12, r5, r2, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalDeselectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r4, r11, r12, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r4, r9, r12, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r7, rB, OUT, OUT, OUT, OUT, OUT },
// { r3, r3, r3, r3, r3, r5, rB, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r4, r9, r12, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r7, rB, OUT, OUT, OUT, OUT },
// { r3, r3, r3, r3, r3, r3, r5, rB, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r4, r9, r12, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r7, rB, OUT, OUT, OUT },
// { r3, r3, r3, r3, r3, r3, r3, r5, rB, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r4, r9, r12, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r7, rB, OUT, OUT },
// { r3, r3, r3, r3, r3, r3, r3, r3, r5, rB, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r4, r9, r12, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r7, rB, OUT },
// { r3, r3, r3, r3, r3, r3, r3, r3, r3, r5, rB, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r4, r9, r12 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB, r4, r3 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, r4, r3, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, r12, r4, rW, rW, r1, r1 },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, OUT, r12, r4, rW, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1 },
// { OUT, OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, r12, r4, rW, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1 },
// { OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, r12, r4, rW, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1 },
// { OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, r12, r4, rW, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1 },
// { OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, r12, r4, rW, r1, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1, r1 },
// { OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1, r1 },
{ r12, r4, rW, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
{ rB, r3, rW, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
{ r3, rW, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
{ rW, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
},
{ // kTabNormalSelectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r4, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, r2, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r4, r11, r12, OUT, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r2, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r4, r11, r12, OUT, OUT, OUT, OUT, OUT },
// { r1, r1, r1, r1, r3, r7, rB, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r2, r7, rB, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r4, r11, r12, OUT, OUT, OUT, OUT },
// { r1, r1, r1, r1, r1, r3, r7, rB, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r2, r7, rB, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r4, r11, r12, OUT, OUT, OUT },
// { r1, r1, r1, r1, r1, r1, r3, r7, rB, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r2, r7, rB, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r4, r11, r12, OUT, OUT },
// { r1, r1, r1, r1, r1, r1, r1, r3, r7, rB, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r2, r7, rB, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r1, r3, r11, r12, OUT },
// { r1, r1, r1, r1, r1, r1, r1, r1, r2, r7, rB, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r7, rB, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r2, r11, rB },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r7, rB },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r3, r3 },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, rW },
},
{ // kTabPressedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB, r11, r11 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, r11, r11, r10, r10 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r12, r11, r10, r10, r9, r9 },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, OUT, r12, r11, r10, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9 },
// { OUT, OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, r12, r11, r10, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9 },
// { OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, r12, r11, r10, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9 },
// { OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, r12, r11, r10, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9 },
// { OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, r12, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9 },
// { OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9 },
{ r12, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9, r9 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabPressedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r11, r7, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r10, r10, r7, r8, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r7, r11, r12, OUT, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r7, r11, r12, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT, OUT },
// { r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r7, r11, r12, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT },
// { r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r7, r11, r12, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT },
// { r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r7, r11, r12, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT },
// { r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r7, r11, r12, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT },
// { r9, r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r9, r7, r11, r12 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
{ // kTabDisabledDeselectedR
{ r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10 },
{ r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
{ // kTabDisabledSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
// { OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
{ // kTabDisabledSelectedR
{ r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
// { r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
};
// These are the color ramp indexes that are used to build the large tab offscreen images.
SInt8 AGATabPanel::kLargeTabImageValues [kNumTabImages] [kLargeTabImageHeight] [kLargeTabImageWidth] =
{
{ // kTabNormalDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB, r5, r3 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, r5, r3, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r12, r5, r2, r2, r3, r3 },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, OUT, r12, r5, r2, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, r12, r5, r2, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, r12, r5, r2, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, r12, r5, r2, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, r12, r5, r2, r3, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3, r3 },
{ OUT, rB, r3, r2, r3, r3, r3, r3, r3, r3, r3, r3 },
{ r12, r5, r2, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalDeselectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r4, r11, r12, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r4, r11, r12, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r7, rB, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r5, rB, OUT, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r4, r11, r12, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r7, rB, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r5, rB, OUT, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r4, r11, r12, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r7, rB, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r5, rB, OUT, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r4, r11, r12, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r7, rB, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r5, rB, OUT, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r4, r11, r12, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r7, rB, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r5, rB, OUT },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r4, r9, r12 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB, r4, r3 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, r4, r3, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, r12, r4, r3, rW, r1, r1 },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, OUT, r12, r4, rW, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, r12, r4, rW, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, r12, r4, rW, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, r12, r4, rW, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, r12, r4, rW, r1, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1, r1 },
{ OUT, rB, r3, rW, r1, r1, r1, r1, r1, r1, r1, r1 },
{ r12, r4, rW, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
{ rB, r3, rW, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
{ r3, rW, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
{ rW, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1 },
},
{ // kTabNormalSelectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r3, r4, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, r2, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r4, r11, r12, OUT, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r2, r7, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r4, r11, r12, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r3, r7, rB, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r2, r7, rB, OUT, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r4, r11, r12, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r3, r7, rB, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r2, r7, rB, OUT, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r4, r11, r12, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r3, r7, rB, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r2, r7, rB, OUT, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r4, r11, r12, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r3, r7, rB, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r2, r7, rB, OUT, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r1, r3, r11, r12, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r1, r2, r7, rB, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r7, rB, OUT },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r2, r11, rB },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r7, rB },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r3, r3 },
{ r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, rW },
},
{ // kTabPressedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, rB, r11, r11 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r12, r11, r11, r10, r10 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r12, r11, r11, r10, r9, r9 },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, OUT, r12, r11, r10, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, r12, r11, r10, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, r12, r11, r10, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, r12, r11, r10, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, r12, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9 },
{ OUT, rB, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9 },
{ r12, r11, r10, r9, r9, r9, r9, r9, r9, r9, r9, r9 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabPressedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r11, r7, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r10, r10, r7, r8, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r7, r11, r12, OUT, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r7, r11, r12, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r7, r11, r12, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r7, r11, r12, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r7, r11, r12, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r7, r11, r12, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r9, r8, rB, OUT },
{ r9, r9, r9, r9, r9, r9, r9, r9, r9, r7, r11, r12 },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3, r3 },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
{ // kTabDisabledDeselectedR
{ r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10 },
{ r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
{ // kTabDisabledSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r10, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ OUT, r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r10, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
{ // kTabDisabledSelectedR
{ r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r10, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10, OUT },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r10 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
{ r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2, r2 },
},
};
// These are the color ramp indexes that are used to build the small 1-bit tab offscreen images.
SInt8 AGATabPanel::k1BitSmallTabImageValues [kNumTabImages] [kSmallTabImageHeight] [kSmallTabImageWidth] =
{
{ // kTabNormalDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalDeselectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalSelectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabPressedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB },
// { OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB },
// { OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB },
// { OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
// { OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
// { OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabPressedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT },
// { rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT },
// { rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT },
// { rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT },
// { rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT },
// { rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledDeselectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
// { OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledSelectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
// { rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
};
// These are the color ramp indexes that are used to build the large 1-bit tab offscreen images.
SInt8 AGATabPanel::k1BitLargeTabImageValues [kNumTabImages] [kLargeTabImageHeight] [kLargeTabImageWidth] =
{
{ // kTabNormalDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalDeselectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabNormalSelectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabPressedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ OUT, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabPressedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, OUT },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledDeselectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledDeselectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledSelectedL
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rB, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ OUT, rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rB, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
{ // kTabDisabledSelectedR
{ rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rB, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB, OUT },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rB },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
{ rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW, rW },
},
};
OSErr AGATabPanel::AllocateTabImages()
{
// Allocate the offscreen images for the various sizes & states.
OSErr result = noErr;
Point imageSize;
if (result == noErr)
{
SetPt(&imageSize, kLargeTabImageWidth, kLargeTabImageHeight);
for (UInt32 imageIndex = 0; (imageIndex < kNumTabImages) && (result == noErr); imageIndex++)
{
mgOffscreenTabImages [imageIndex] [kLargeTabImages] = new AGAOffscreenImage;
result = mgOffscreenTabImages [imageIndex] [kLargeTabImages] ->CreateImageData(
imageSize,
&kLargeTabImageValues[imageIndex][0][0],
NULL,
&gAGARamp[r2]);
}
}
if (result == noErr)
{
SetPt(&imageSize, kSmallTabImageWidth, kSmallTabImageHeight);
for (UInt32 imageIndex = 0; (imageIndex < kNumTabImages) && (result == noErr); imageIndex++)
{
mgOffscreenTabImages [imageIndex] [kSmallTabImages] = new AGAOffscreenImage;
result = mgOffscreenTabImages [imageIndex] [kSmallTabImages] ->CreateImageData(
imageSize,
&kSmallTabImageValues[imageIndex][0][0],
NULL,
&gAGARamp[r2]);
}
}
if (result == noErr)
{
SetPt(&imageSize, kLargeTabImageWidth, kLargeTabImageHeight);
for (UInt32 imageIndex = 0; (imageIndex < kNumTabImages) && (result == noErr); imageIndex++)
{
mg1BitOffscreenTabImages [imageIndex] [kLargeTabImages] = new AGAOffscreenImage;
result = mg1BitOffscreenTabImages [imageIndex] [kLargeTabImages] ->CreateImageData(
imageSize,
&k1BitLargeTabImageValues[imageIndex][0][0],
NULL,
&gAGARamp[r2]);
}
}
if (result == noErr)
{
SetPt(&imageSize, kSmallTabImageWidth, kSmallTabImageHeight);
for (UInt32 imageIndex = 0; (imageIndex < kNumTabImages) && (result == noErr); imageIndex++)
{
mg1BitOffscreenTabImages [imageIndex] [kSmallTabImages] = new AGAOffscreenImage;
result = mg1BitOffscreenTabImages [imageIndex] [kSmallTabImages] ->CreateImageData(
imageSize,
&k1BitSmallTabImageValues[imageIndex][0][0],
NULL,
&gAGARamp[r2]);
}
}
return result;
}
void AGATabPanel::CopyTabImage(UInt32 imageIndex, Point imageDestination, Boolean deep)
{
// Blast the specified offscreen image into the radio button's button area.
if (deep)
mgOffscreenTabImages [imageIndex] [(mTabSize == kSmallTabs) ? kSmallTabImages : kLargeTabImages]->DrawImage(imageDestination.h, imageDestination.v);
else
mg1BitOffscreenTabImages [imageIndex] [(mTabSize == kSmallTabs) ? kSmallTabImages : kLargeTabImages]->DrawImage(imageDestination.h, imageDestination.v);
}
void AGATabPanel::DisposeTabImages()
{
for (UInt32 imageIndex = 0; imageIndex < kNumTabImages; imageIndex++)
if (mgOffscreenTabImages [imageIndex] [kLargeTabImages] != NULL)
delete mgOffscreenTabImages [imageIndex] [kLargeTabImages];
for (UInt32 imageIndex = 0; imageIndex < kNumTabImages; imageIndex++)
if (mgOffscreenTabImages [imageIndex] [kSmallTabImages] != NULL)
delete mgOffscreenTabImages [imageIndex] [kSmallTabImages];
for (UInt32 imageIndex = 0; imageIndex < kNumTabImages; imageIndex++)
if (mg1BitOffscreenTabImages [imageIndex] [kLargeTabImages] != NULL)
delete mg1BitOffscreenTabImages [imageIndex] [kLargeTabImages];
for (UInt32 imageIndex = 0; imageIndex < kNumTabImages; imageIndex++)
if (mg1BitOffscreenTabImages [imageIndex] [kSmallTabImages] != NULL)
delete mg1BitOffscreenTabImages [imageIndex] [kSmallTabImages];
}
//
// AGAStringOut --------------------------------------------------------
//
// This is the routine we use for all of our one-line text output.
//
void AGAStringOut(StringPtr aString,
Rect* centeringFrame,
SInt32 truncation,
SInt32 justification,
AGAStringOutColor outColor,
Boolean deep,
const AGATextStyle& textStyle)
{
Str255 outputString;
FontInfo fontInfo;
SInt16 frameWidth = centeringFrame->right - centeringFrame->left;
SInt16 frameHeight = centeringFrame->bottom - centeringFrame->top;
Point penOrigin;
Boolean setColor = true;
UInt8 colorIndex;
textStyle.PrepareForDrawing();
::GetFontInfo(&fontInfo);
switch (outColor)
{
case kNormalOutput:
colorIndex = rB;
break;
case kDisabledOutput:
if (deep)
colorIndex = r7;
else
colorIndex = rB;
break;
case kInverseOutput:
colorIndex = rW;
break;
case kUseCurrentColor:
setColor = false;
break;
}
if (setColor)
::RGBForeColor(&gAGARamp[colorIndex]);
AGA_PLstrcpy(outputString, aString);
// Truncate the string if it does not fit the width of the frame.
if (truncation != kNoTruncation)
{
// If the string would be truncated at the current
// font settings, try again with condensed text.
if (::TruncString(frameWidth, outputString, truncation) == truncated)
{
AGA_PLstrcpy(outputString, aString);
::TextFace(condense);
(void) ::TruncString(frameWidth, outputString, truncation);
}
}
// Center the text vertically. Pen goes at baseline of
// text, i.e. between the ascent and descent.
penOrigin.v = centeringFrame->top + (frameHeight / 2) + ((fontInfo.ascent + fontInfo.descent) / 2) - fontInfo.descent;
// Position the text horizontally left, centered, or right, based
// on the specified justification and the system script direction.
switch (RuntimeJustify(justification))
{
case teCenter:
penOrigin.h = centeringFrame->left + (frameWidth / 2) - (::StringWidth(outputString) / 2);
break;
case teFlushRight:
penOrigin.h = centeringFrame->right - ::StringWidth(outputString);
break;
default: //case teFlushLeft:
penOrigin.h = centeringFrame->left;
break;
}
::MoveTo(penOrigin.h, penOrigin.v);
GrafPtr currentPort;
::GetPort(¤tPort);
SInt16 savedTxMode = currentPort->txMode;
::TextMode(srcOr);
::DrawString(outputString);
::TextMode(savedTxMode);
if ((outColor == kDisabledOutput) && ! deep)
{
::PenPat(&qd.gray);
::PenMode(patBic);
::PaintRect(centeringFrame);
::PenNormal();
}
}
//
// AGATextBox --------------------------------------------------------
//
// This is a replacement for TETextBox.
//
void AGATextBox(const void *textPtr,
SInt32 textLength,
const Rect *textFrame,
SInt16 justification,
AGAStringOutColor outColor,
Boolean deep,
const AGATextStyle& textStyle,
const RGBColor* teBackgroundColor)
{
FontInfo fontInfo;
Boolean setColor = true;
UInt8 colorIndex;
RGBColor savedBackColor;
::GetBackColor(&savedBackColor);
::RGBBackColor(teBackgroundColor);
textStyle.PrepareForDrawing();
::GetFontInfo(&fontInfo);
switch (outColor)
{
case kNormalOutput:
colorIndex = rB;
break;
case kDisabledOutput:
if (deep)
colorIndex = r7;
else
colorIndex = rB;
break;
case kInverseOutput:
colorIndex = rW;
break;
case kUseCurrentColor:
setColor = false;
break;
}
if (setColor)
::RGBForeColor(&gAGARamp[colorIndex]);
::TETextBox(textPtr, textLength, textFrame, justification);
if ((outColor == kDisabledOutput) && ! deep)
{
::PenPat(&qd.gray);
::PenMode(patBic);
::PaintRect(textFrame);
::PenNormal();
}
::RGBBackColor(&savedBackColor);
}
//
// GDIterator -----------------------------------------------------
//
RgnHandle GDIterator::mSavedClipping = ::NewRgn();
GDIterator::GDIterator()
{
this->Setup();
}
GDIterator::~GDIterator()
{
this->Cleanup();
}
void GDIterator::Setup()
{
// Save the current clipping so we can put it back in Cleanup
// and use it as we iterate over each device.
::GetClip(mSavedClipping);
mIteratedYet = false;
mCurrentGDHandle = NULL;
}
Boolean GDIterator::More(Boolean& deep)
{
// If there's another device to draw on, get its GDHandle and deepness,
// and return true. Otherwise, return false.
if (gAGAHasColorQD)
{
mCurrentGDHandle = this->FindNextValidDevice(mCurrentGDHandle, deep);
return (mCurrentGDHandle != NULL);
}
else
{
deep = false;
return ! mIteratedYet;
}
}
void GDIterator::Cleanup()
{
// Restore clipping to what it was when we were constructed.
::SetClip(mSavedClipping);
}
void GDIterator::ClipFurtherToCurrentDevice()
{
// Clip further to prevent drawing outside the current device.
this->ClipFurtherToDevice(mCurrentGDHandle);
}
GDHandle GDIterator::FindNextValidDevice(GDHandle currentDevice, Boolean& deep)
{
// Return the GDHandle of the next valid device, if any, and indicate
// whether it is "deep".
// As a designed side-effect, when we find a next device, we restore
// the original clipping and then re-clip further to this next device
// so no drawing occurs on other devices.
GDHandle deviceToTest;
GDHandle deviceFound = NULL;
deep = false;
if (currentDevice == NULL)
deviceToTest = ::GetDeviceList();
else
deviceToTest = ::GetNextDevice(currentDevice);
while ((deviceToTest != NULL) && (deviceFound == NULL))
{
Boolean isValidDevice = false;
if (::TestDeviceAttribute(deviceToTest, screenDevice))
if (::TestDeviceAttribute(deviceToTest, screenActive))
{
isValidDevice = true;
SInt16 pixelDepth = (**((**deviceToTest).gdPMap)).pixelSize;
Boolean isColor = ::TestDeviceAttribute(deviceToTest, gdDevType);
deep = (pixelDepth >= kDeepColorBits) || ((pixelDepth >= kDeepGrayscaleBits) && ! isColor);
deviceFound = deviceToTest;
}
if (! isValidDevice)
deviceToTest = ::GetNextDevice(deviceToTest);
}
if (deviceFound != NULL)
{
::SetClip(mSavedClipping);
this->ClipFurtherToDevice(deviceFound);
}
return deviceFound;
}
void GDIterator::ClipFurtherToDevice(GDHandle aDevice)
{
// Clip further to the specified device so no drawing will occur
// on other devices.
if (aDevice != NULL)
{
Rect deviceRect = (**aDevice).gdRect;
Point drTopLeft;
Point drBotRight;
::SetPt(&drTopLeft, deviceRect.left, deviceRect.top);
::SetPt(&drBotRight, deviceRect.right, deviceRect.bottom);
::GlobalToLocal(&drTopLeft);
::GlobalToLocal(&drBotRight);
::SetRect(&deviceRect, drTopLeft.h, drTopLeft.v, drBotRight.h, drBotRight.v);
AGAClipFurther(&deviceRect);
}
}
//
// AGABackgroundPaint ------------------------------------------------
//
void AGABackgroundPaint(const Rect* backgroundBounds,
Boolean drawFill,
AGABackgroundKind backgroundKind,
Boolean isActive,
Boolean hasGrowBox)
{
if (backgroundKind == kNoBackgroundPaint)
return;
AGADrawingEnvironment env;
// Draw in the specified active/inactive state.
enum { kBGFill, kBGActiveLight, kBGActiveShadow, kBGActiveCorner, kBGInactiveLight, kBGInactiveShadow, kBGInactiveCorner, kBGNumIndexes };
UInt8 colorIndexes[kBGNumIndexes];
switch (backgroundKind)
{
case kRaisedModelessBackground:
colorIndexes[kBGFill] = r2;
colorIndexes[kBGActiveLight] = rW;
colorIndexes[kBGActiveShadow] = r6;
colorIndexes[kBGActiveCorner] = r2;
colorIndexes[kBGInactiveLight] = r2;
colorIndexes[kBGInactiveShadow] = r2;
colorIndexes[kBGInactiveCorner] = r2;
break;
case kRaisedModalBackground:
colorIndexes[kBGFill] = r2;
colorIndexes[kBGActiveLight] = rW;
colorIndexes[kBGActiveShadow] = r6;
colorIndexes[kBGActiveCorner] = r4;
colorIndexes[kBGInactiveLight] = r2;
colorIndexes[kBGInactiveShadow] = r2;
colorIndexes[kBGInactiveCorner] = r2;
break;
case kFlatWindowBackground:
colorIndexes[kBGFill] = r2;
colorIndexes[kBGActiveLight] = r2;
colorIndexes[kBGActiveShadow] = r2;
colorIndexes[kBGActiveCorner] = r2;
colorIndexes[kBGInactiveLight] = r2;
colorIndexes[kBGInactiveShadow] = r2;
colorIndexes[kBGInactiveCorner] = r2;
break;
}
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
Rect r = *backgroundBounds;
if (deep)
{
::InsetRect(&r, 1, 1);
if (drawFill)
{
::RGBForeColor(&gAGARamp[colorIndexes[kBGFill]]);
::PaintRect(&r);
}
if (isActive)
::RGBForeColor(&gAGARamp[colorIndexes[kBGActiveCorner]]);
else
::RGBForeColor(&gAGARamp[colorIndexes[kBGInactiveCorner]]);
::MoveTo(r.left - 1, r.bottom);
::Line(0, 0);
::MoveTo(r.right, r.top - 1);
::Line(0, 0);
if (isActive)
::RGBForeColor(&gAGARamp[colorIndexes[kBGActiveLight]]);
else
::RGBForeColor(&gAGARamp[colorIndexes[kBGInactiveLight]]);
::MoveTo(r.left - 1, r.bottom - 1);
::LineTo(r.left - 1, r.top - 1);
::LineTo(r.right - 1, r.top - 1);
if (isActive)
::RGBForeColor(&gAGARamp[colorIndexes[kBGActiveShadow]]);
else
::RGBForeColor(&gAGARamp[colorIndexes[kBGInactiveShadow]]);
::MoveTo(r.left, r.bottom);
if (hasGrowBox)
{
::LineTo(r.right - 15, r.bottom);
::Line(0, -15);
::Line(15, 0);
}
else
::LineTo(r.right, r.bottom);
::LineTo(r.right, r.top);
}
else // 1-bit
{
if (drawFill)
{
::RGBBackColor(&gAGARamp[rW]);
::EraseRect(&r);
}
}
}
}
//
// AGAInstallGrayWCTB ------------------------------------------------
//
OSErr AGAInstallGrayWCTB(WindowPtr aWindow)
{
//
// If it's a color window, make a copy of the default
// color table, set the background to r2, and install
// it into the window.
//
OSErr err = noErr;
AuxWinHandle auxWinHandle;
CTabHandle colorTableHandle;
::GetAuxWin(NULL, &auxWinHandle);
if (auxWinHandle != NULL)
{
colorTableHandle = (**auxWinHandle).awCTable;
err = ::HandToHand((Handle*) &colorTableHandle);
if (err == noErr)
{
(**colorTableHandle).ctTable->rgb = gAGARamp[r2];
::SetWinColor(aWindow, (WCTabHandle) colorTableHandle);
}
}
return err;
}
//
// AGADrawBorderFrame ------------------------------------------------
//
void AGADrawBorderFrame(const Rect* bounds, Boolean isEnabled, Boolean isNotched, Boolean drawFrame, const RGBColor* windowBackgroundColor)
{
// Draw the frame with shading outside.
enum { Shadow, Frame, Light, kNumColors };
Rect r = *bounds;
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
AGADrawingEnvironment env;
if (drawFrame)
{
if (deep)
{
if (isEnabled)
::RGBForeColor(&gAGARamp[rB]);
else
::RGBForeColor(&gAGARamp[r10]);
}
else
{
::RGBForeColor(&gAGARamp[rB]);
if (isEnabled)
::PenPat(&qd.black);
else
::PenPat(&qd.gray);
}
::InsetRect(&r, 1, 1);
if (isNotched)
{
::MoveTo(r.right - 1, r.top);
::LineTo(r.left, r.top);
::LineTo(r.left, r.bottom - 1);
::LineTo(r.right - 16, r.bottom - 1);
::Line(0, -15);
::Line(15, 0);
::LineTo(r.right - 1, r.top);
}
else
::FrameRect(&r);
::InsetRect(&r, -1, -1);
}
if (deep)
{
if (isEnabled)
::RGBForeColor(&gAGARamp[r5]);
else
::RGBForeColor(windowBackgroundColor);
::MoveTo(r.left, r.bottom - 2);
::LineTo(r.left, r.top);
::LineTo(r.right - 2, r.top);
if (isEnabled)
::RGBForeColor(&gAGARamp[rW]);
else
::RGBForeColor(windowBackgroundColor);
::MoveTo(r.left + 1, r.bottom - 1);
if (isNotched)
{
::LineTo(r.right - 16, r.bottom - 1);
::Line(0, -15);
::Line(15, 0);
}
else
::LineTo(r.right - 1, r.bottom - 1);
::LineTo(r.right - 1, r.top + 1);
}
}
}
//
// AGAComputeTargetBorderRegion ------------------------------------------------
//
void AGAComputeTargetBorderRegion(RgnHandle borderRegion, const Rect* bounds, Boolean isNotched)
{
// Compute the border region to be painted.
RgnHandle innerRegion = ::NewRgn();
Rect r = *bounds;
// First create a region framing the outer edge of the border.
::OpenRgn();
::FrameRoundRect(&r, 4, 4);
::CloseRgn(borderRegion);
// Now subtract away the hollow inside area.
::InsetRect(&r, 2, 2);
::RectRgn(innerRegion, &r);
::DiffRgn(borderRegion, innerRegion, borderRegion);
if (isNotched)
{
// OK, region madness as we add the top/left sides
// of a new "notch" rect frame, and also remove the
// bottom/right corner of our existing non-notched frame.
RgnHandle notchRegion = ::NewRgn();
Rect notchRect;
// Create a new round rect for the corner area and
// union it with the existing region.
notchRect = *bounds;
notchRect.left = notchRect.right - 17;
notchRect.top = notchRect.bottom - 17;
::RectRgn(notchRegion, ¬chRect);
::UnionRgn(borderRegion, notchRegion, borderRegion);
// Subtract away the corner of the existing frame.
notchRect.left += 2;
notchRect.top += 2;
::RectRgn(notchRegion, ¬chRect);
::DiffRgn(borderRegion, notchRegion, borderRegion);
// Almost done. There's an extra pixel at each notch
// corner that needs to be removed to make round corners.
Rect pixelRect;
// The top/right corner.
pixelRect = notchRect;
pixelRect.left = pixelRect.right - 1;
pixelRect.top--;
pixelRect.bottom = pixelRect.top + 1;
::RectRgn(notchRegion, &pixelRect);
::DiffRgn(borderRegion, notchRegion, borderRegion);
// The bottom/left corner.
pixelRect = notchRect;
pixelRect.top = pixelRect.bottom - 1;
pixelRect.left--;
pixelRect.right = pixelRect.left + 1;
::RectRgn(notchRegion, &pixelRect);
::DiffRgn(borderRegion, notchRegion, borderRegion);
// The top/left corner.
pixelRect = notchRect;
pixelRect.top -= 2;
pixelRect.left -= 2;
pixelRect.bottom = pixelRect.top + 1;
pixelRect.right = pixelRect.left + 1;
::RectRgn(notchRegion, &pixelRect);
::DiffRgn(borderRegion, notchRegion, borderRegion);
::DisposeRgn(notchRegion);
}
::DisposeRgn(innerRegion);
}
//
// AGAClipFurther ------------------------------------------------
//
void AGAClipFurther(Rect* clippingRect)
{
// Shrink the clip region further to prevent drawing outside
// the specified rect.
RgnHandle oldClip = ::NewRgn();
RgnHandle newClip = ::NewRgn();
if ((oldClip != NULL) && (newClip != NULL))
{
::GetClip(oldClip);
::RectRgn(newClip, clippingRect);
::SectRgn(oldClip, newClip, newClip);
::SetClip(newClip);
::DisposeRgn(oldClip);
::DisposeRgn(newClip);
}
}
//
// AGA_PLstrcpy ------------------------------------------------
//
void AGA_PLstrcpy(StringPtr str1, ConstStr255Param str2)
{
// Copy pascal string str2 into pascal string str1.
::BlockMoveData((Ptr) str2, (Ptr) str1, 1 + str2[0]);
}
//
// AGA Defaults ------------------------------------------------
//
void SetGrayCouncilDefault(UInt32 itemMask, Boolean turnOn)
{
if (turnOn)
gAGADefaults |= itemMask;
else
gAGADefaults &= ~itemMask;
}
Boolean TestGrayCouncilDefault(UInt32 itemMask)
{
return ((gAGADefaults & itemMask) != 0);
}
//
// Variable-color background support -------------------------------
//
// Tab panels provide us a more complicated background color situation
// than other situations. While the normal AGA background is gray ramp
// value r2, the tab panels are lighter, namely r1. However, when a tab
// panel is dimmed, it becomes r2. Thus the panel subpanes can't just
// blindly use the window background color, and if the tab panel becomes
// dimmed they can't just blindly use r1 either.
//
// So what we do is maintain static color values that are picked up by
// any adapter classes that need to erase their background. There are
// separate color values for enabled and disabled states. When a panel
// view hierarchy is installed into a tab panel pane, the tab panel class
// temporarily sets these color values so that any subpanes of the panel
// will pick them up as they are instantiated.
//
static Boolean gUseSpecialBackgroundColors = false; // toggled by tab panel installer
static RGBColor gEnabledBackgroundColor;
static RGBColor gDisabledBackgroundColor;
Boolean DetermineAGABackgroundColors(RGBColor* enabledColor, RGBColor* disabledColor, Boolean installIfNotCustom)
{
Boolean wereColorsSet = false;
if (gUseSpecialBackgroundColors)
{
*enabledColor = gEnabledBackgroundColor;
*disabledColor = gDisabledBackgroundColor;
wereColorsSet = true;
}
else if (installIfNotCustom)
{
// The calling view must have focused and set the port bg color.
::GetBackColor(enabledColor);
*disabledColor = *enabledColor;
wereColorsSet = true;
}
return wereColorsSet;
}
void InstallAGABackgroundColors(AGAObject* itsAGAObject, Boolean installIfNotCustom)
{
RGBColor enabledColor;
RGBColor disabledColor;
if (DetermineAGABackgroundColors(&enabledColor, &disabledColor, installIfNotCustom))
itsAGAObject->SetBackgroundColors(&enabledColor, &disabledColor);
}
void TurnOnCustomAGABackgroundColors(RGBColor* enabledColor, RGBColor* disabledColor)
{
gUseSpecialBackgroundColors = true;
gEnabledBackgroundColor = *enabledColor;
gDisabledBackgroundColor = *disabledColor;
}
void TurnOffCustomAGABackgroundColors()
{
gUseSpecialBackgroundColors = false;
}
//
// Global variables ---------------------------------------------------
//
const Str255 gGrayCouncilCopyright = kGrayCouncilCopyright;
Boolean gAGAHasColorQD;
UInt32 gAGADefaults = 0;
AGAGroupsContainer* gGroupsContainer;
// Standard system text style, used by most standard controls.
AGATextStyle gAGAStdSystemStyle = AGATextStyle();
// Standard small text style, used for slider labels.
AGATextStyle gAGAStdSmallStyle = AGATextStyle(applFont, 10, normal);
// Standard small bold text style, used for small tab panels.
AGATextStyle gAGAStdBoldSmallStyle = AGATextStyle(applFont, 10, bold);
// Extra small text style, a de facto standard.
AGATextStyle gAGAExtraSmallStyle = AGATextStyle(applFont, 9, normal);
// These are the AGA-specified color values.
RGBColor gAGARamp[kNumRampColors] =
{
{65535, 65535, 65535}, // rW white
{61166, 61166, 61166}, // r1 lightest gray
{56797, 56797, 56797}, // r2
{52428, 52428, 52428}, // r3
{48059, 48059, 48059}, // r4 light grays
{43690, 43690, 43690}, // r5
{39321, 39321, 39321}, // r6
{34952, 34952, 34952}, // r7
{30583, 30583, 30583}, // r8 dark grays
{26214, 26214, 26214}, // r9
{21845, 21845, 21845}, // r10
{17476, 17476, 17476}, // r11
{13107, 13107, 13107}, // r12 darkest "n" gray
{8738, 8738, 8738}, // rA1 additional darker gray value 1
{4369, 4369, 4369}, // rA2 additional darker gray value 2
{0, 0, 0}, // rB black
{52428, 52428, 65535}, // rP1 lightest purple
{39321, 39321, 65535}, // rP2 light purple
{26214, 26214, 65535}, // rP3 dark purple
{13107, 13107, 26214} // rP4 darkest purple
};