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.