This is MiscArrowButtonCell.m in view mode; [Download] [Up]
// Copyright (C) 1995 Robert Todd Thomas
// Use is governed by the MiscKit license
/******************************************************************
* CLASS: MiscArrowButtonCell
*
* See the header for more information on this class.
*
* This object is included in the MiscKit by permission from the author
* and its use is governed by the MiscKit license, found in the file
* "LICENSE.rtf" in the MiscKit distribution. Please refer to that file
* for a list of all applicable permissions and restrictions.
*******************************************************************/
#import "wraps.h"
#import <dpsclient/psops.h>
#import <apps/InterfaceBuilder.h>
#import "MiscArrowButtonCell.h"
// These #defines are used for versioning instances of this class, so that
// you will always be able to read any previously archived version. If you
// make changes to the class's ivars, bump the version number up one and
// make the appropriate changes to the read: method.
#define MISC_ABC_VERSION 1
#define MISC_ABC_CLASSNAME "MiscArrowButtonCell"
@implementation MiscArrowButtonCell
+ initialize
{
if (self == [MiscArrowButtonCell class])
[self setVersion: MISC_ABC_VERSION];
return self;
}
// The initializing methods just call the designated initializer
// and give some default values.
- init
{
return [self initTextCell: "Left" altTitle: "Right"];
}
- initTextCell: (const char *)aString
{
return [self initTextCell: aString altTitle: "Right"];
}
// The desinated initializer for this class.
- initTextCell: (const char *)aString altTitle: (const char *)altString
{
[super initTextCell: aString];
[self setAltTitle: altString];
[self setState: 0];
[self setBordered: NO];
[self setShowsStateBy: NX_NONE];
[self setHighlightsBy: NX_NONE];
[self setArrowAlignment: MISC_ARROW_ABSOLUTE];
[self setType: NX_TOGGLE];
return self;
}
// Since the stringValue in Button does not do much, it now
// returns the currently selected text.
- (const char *)stringValue
{
if ([self state] == 0)
return (const char *)[self title];
else
return (const char *)[self altTitle];
}
// I believe this method is supposed to calculate the minimum size needed to
// fit the currently displayed contents (contents, altContents, and the arrow)
// in the cellframe.
- calcCellSize: (NXSize *)theSize inRect: (NXRect *)theRect
{
float contentsWidth = [ [self font] getWidthOf: [self title] ];
float altContentsWidth = [ [self font] getWidthOf: [self altTitle] ];
// first calculate the width needed to draw all text and the arrow
theSize->width = 0.0;
if ([self arrowAlignment] == MISC_ARROW_RELATIVE)
{
theSize->width += contentsWidth;
theSize->width += altContentsWidth;
}
else // absolute alignment
{
if (contentsWidth > altContentsWidth)
theSize->width += contentsWidth * 2.0;
else
theSize->width += altContentsWidth * 2.0;
}
theSize->width += cellHeight + 10.0;
// now the height (which will usually be cellHeight)
theSize->height = cellHeight;
if ([ [self font] pointSize] > cellHeight)
theSize->height = [ [self font] pointSize];
return self;
}
// As far as I can tell (which may not be all that far) is that this
// function is only used by the Button's IBEditor to tell how large
// the editor should be.
- getTitleRect : (NXRect *)theRect
{
float size = [ [self font] pointSize];
float theY;
float maxWidth = theRect->size.width/2.0;
// this is a hack so you can double click on the altTitle in IB
if ([self state])
return [self getAltTitleRect: theRect];
[self setAlignment: NX_LEFTALIGNED]; // used for the IBEditor
theY = theRect->origin.y + theRect->size.height/2.0 - size/2.0;
if ([self arrowAlignment] == MISC_ARROW_RELATIVE)
maxWidth = [ [self font] getWidthOf: [self title] ] + 10.0;
NXSetRect (theRect, theRect->origin.x, theY-2.0, maxWidth, size+2.0);
return self;
}
// If the state is 1 (altContents selected), then this method will be
// called. It returns the location for editor to appear when editing
// the altContents.
- getAltTitleRect: (NXRect *)theRect
{
float size = [ [self font] pointSize];
float newX, newY, newWidth;
[self setAlignment: NX_RIGHTALIGNED]; // used for the IBEditor
newX = theRect->origin.x + theRect->size.width/2.0;
newY = theRect->origin.y + theRect->size.height/2.0 - size/2.0;
newWidth = theRect->size.width/2.0;
NXSetRect (theRect, newX, newY-2.0, newWidth, size+2.0);
return self;
}
// New method to set the alignment of the arrow. MISC_ARROW_ABSOLUTE aligns
// the arrow in the center of the cellFrame, where MISC_ARROW_RELATIVE
// centers the arrow between the contents and altContents.
- setArrowAlignment: (int)alignment
{
arrowAlignment = alignment;
return self;
}
- (int)arrowAlignment
{
return arrowAlignment;
}
// This method is used to draw only the parts of the cell that
// do change when the state changes. Therefore, only the black arrow
// and the text are drawn here.
- drawInside: (const NXRect *)cellFrame inView: controlView
{
float gray;
float size = [ [self font] pointSize];
// draw the arrow
if ([self arrowAlignment] == MISC_ARROW_RELATIVE)
{
NXRect relativeFrame;
float contentsWidth = [ [self font] getWidthOf: [self title] ];
float altContentsWidth = [ [self font] getWidthOf: [self altTitle] ];
// since it the arrow is drawn relative to the text, a little
// calculation is needed
relativeFrame.origin.x = cellFrame->origin.x + contentsWidth;
relativeFrame.size.width = cellFrame->size.width -
(contentsWidth + altContentsWidth);
PSABdrawarrow (relativeFrame.origin.x, cellFrame->origin.y + 3.0,
relativeFrame.size.width, cellFrame->size.height - 6.0,
(int)[self state], [self isEnabled]);
}
else
// draw the arrow in the center of the cellFrame
PSABdrawarrow (cellFrame->origin.x, cellFrame->origin.y + 3.0,
cellFrame->size.width, cellFrame->size.height - 6.0,
(int)[self state], [self isEnabled]);
// draw the left and right hand text
[ [self font] set];
if ([self title] != NULL)
{
float theY;
if ([self state] || ![self isEnabled])
gray = NX_DKGRAY;
else
gray = 0.0;
// calculate the placement of the contents and print it
theY = cellFrame->origin.y + cellFrame->size.height/2.0 + size/3.0;
PSABshowstring (cellFrame->origin.x + 3.0, theY, gray, [self title]);
}
if ([self altTitle] != NULL)
{
float theX, theY;
float strWidth = [ [self font] getWidthOf: [self altTitle] ];
if ([self state] && [self isEnabled])
gray = 0.0;
else
gray = NX_DKGRAY;
// calculate the placement of the altContents and print it
theX = cellFrame->origin.x+(cellFrame->size.width - strWidth - 3.0);
theY = cellFrame->origin.y + cellFrame->size.height/2.0 + size/3.0;
PSABshowstring (theX, theY, gray, [self altTitle]);
}
return self;
}
// This part of the drawing displays only the parts that don't change
// often, which includes the diamond that encloses the arrow, and the
// border when I get around to adding one.
- drawSelf: (const NXRect *)cellFrame inView: controlView
{
// if transparent draw the background white (when in IB) and
// same as the background when in an app (or testing interface)
if ([self isTransparent])
{
if ([NXApp respondsTo: @selector(isTestingInterface)])
if ([NXApp isTestingInterface])
PSsetgray (NX_LTGRAY);
else
PSsetgray (1.0);
else
PSsetgray (NX_LTGRAY);
NXRectFill (cellFrame);
return self;
}
// set cellHeight since some of the calculations that are in other
// methods have to know the height of the cell (this is probably the
// wrong way to go about this)
cellHeight = cellFrame->size.height;
// draw the border or bezel, then call drawInside
if ([self isBordered])
NXDrawButton (cellFrame, cellFrame);
PSgsave();
// have to flip drawing if we are drawing into a flipped view
if ([controlView isFlipped])
PSABflipme (cellFrame->size.height + (cellFrame->origin.y * 2.0));
if ([self arrowAlignment] == MISC_ARROW_RELATIVE)
{
NXRect relativeFrame;
float contentsWidth = [ [self font] getWidthOf: [self title] ];
float altContentsWidth = [ [self font] getWidthOf: [self altTitle] ];
relativeFrame.origin.x = cellFrame->origin.x + contentsWidth;
relativeFrame.size.width = cellFrame->size.width -
(contentsWidth + altContentsWidth);
PSABdrawdiamond (relativeFrame.origin.x, cellFrame->origin.y + 3.0,
relativeFrame.size.width, cellFrame->size.height - 6.0);
}
else
PSABdrawdiamond (cellFrame->origin.x, cellFrame->origin.y + 3.0,
cellFrame->size.width, cellFrame->size.height - 6.0);
PSgrestore();
// draw the rest of the cell
[self drawInside: cellFrame inView: controlView];
return self;
}
// Archiving methods
- read: (NXTypedStream *)stream
{
int version;
[super read: stream];
version = NXTypedStreamClassVersion (stream, MISC_ABC_CLASSNAME);
switch (version)
{
case 0:
// First version had no ivars, but set any new ivars to a useable
// value.
arrowAlignment = MISC_ARROW_ABSOLUTE;
break;
case 1:
// Current version.
NXReadType (stream, @encode(unsigned int), &arrowAlignment);
break;
default:
break;
}
return self;
}
- write: (NXTypedStream *)stream
{
[super write: stream];
// You can also keep versioning here just in case you would like
// to back to an older version, but I don't.
NXWriteType (stream, @encode(unsigned int), &arrowAlignment);
return self;
}
@end
/******************************************************************
CHANGES:
1. Now use setArrowAlignment/arrowAlignment to set/get whether the
the arrow is relative or absolutely aligned. Added arrowAlignment
instance var.
October 1, 1994:
2. Added archive versioning (+initialize).
*******************************************************************/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.