home *** CD-ROM | disk | FTP | other *** search
- // Ruler.m
- // A general ruler class designed to be used with the RuledScrollView class
-
- #import <dpsclient/psops.h>
- #import <libc.h> // for atoi and strrchr
- #import <math.h>
- #import <appkit/Font.h>
- #import <appkit/ScrollView.h>
- #import <appkit/Application.h> // for NXApp method
-
- #import "RuledScrollView.h" // for retrieving rulers
-
- #import "Ruler.h"
- #define DEFAULTSCALESPACING (72*0.39)
-
- @implementation Ruler
-
-
- /* instance methods */
- /* Initializing and freeing an instance */
- - initFrame:(NXRect *)frameRect
- {
- [super initFrame:frameRect];
-
- scaleSpacing = DEFAULTSCALESPACING;
- orientation = HORIZONTAL;
- inverted = NO;
- mirrored = NO;
- scale = 1.0;
- scaleOffset = 0;
- border = 0.0;
- scaleSpacing = DEFAULTSCALESPACING;
- alignment = NX_CENTERED;
- leftOrBottomMargin = 0;
- rightOrTopMargin = 0;
- backgroundColor = NXConvertRGBToColor(1.0,1.0,1.0);
- backgroundGray = NX_LTGRAY;
- draggableRuler = NO;
- units = malloc(2*sizeof(char));
- strcpy(units,"\0");
-
- font = [Font newFont:"Helvetica" size:12 style:0 matrix:NX_IDENTITYMATRIX];
- NXTextFontInfo(font, &ascender, &descender, &lineHeight);
-
- return self;
- }
-
- - free
- {
- if (units) free(units);
- return [super free];
- }
-
- /* Drawing the view */
- - drawSelf:(NXRect *)rects :(int)rectCount
- {
- char buf[25];
- float r,g,b;
- int j,start,end;
- float x0,y0,x1,y1,measure, halfWidth;
- float vtextOffset,htextOffset;
-
- x0 = rects[0].origin.x;
- y0 = rects[0].origin.y;
- x1 = x0 + rects[0].size.width;
- y1 = y0 + rects[0].size.height;
-
- NXConvertColorToRGB(backgroundColor, &r, &g, &b);
- if ((r!=1.0) || (g!=1.0) || (b!=1.0)) {
- PSsetrgbcolor(r,g,b);
- }
- else
- PSsetgray(backgroundGray);
- NXRectFill(&(rects[0]));
-
- [font set];
- // draw a line along the edge of the ruler next to the 'rulered view'
- PSsetgray(NX_BLACK);
- PSsetlinewidth(0.0);
- if (orientation == HORIZONTAL) {
- if (inverted) {
- PSmoveto(x0,1);
- PSlineto(x1,1);
- }
- else {
- PSmoveto(x0,bounds.size.height);
- PSlineto(x1,bounds.size.height);
- }
- }
- else {
- if (inverted) {
- PSmoveto(0,y0);
- PSlineto(0,y1);
- }
- else {
- PSmoveto(bounds.size.width-1,y0);
- PSlineto(bounds.size.width-1,y1);
- }
- }
- PSstroke();
-
- // draw measures
-
- if (orientation == HORIZONTAL) {
- start = (int)floor((double)(x0/scaleSpacing))-2;
- end = (int)ceil((double)(x1/scaleSpacing))+1;
- }
- else {
- start = (int)floor((double)(y0/scaleSpacing))-2;
- end = (int)ceil((double)(y1/scaleSpacing))+1;
- }
- for(j=start; j<=end; j++) {
- measure = j*scale+scaleOffset;
-
- sprintf(buf,"%.4g",measure);
- strcatn(buf,units,23-strlen(buf));
- halfWidth = [font getWidthOf:buf]/2;
- switch (alignment) {
- case NX_LEFTALIGNED:
- htextOffset = 2;
- break;
- case NX_RIGHTALIGNED:
- if (orientation == HORIZONTAL)
- htextOffset = -2-(halfWidth*2);
- else
- htextOffset = bounds.size.width-2-(halfWidth*2);
- break;
- default: // default is centered
- if (orientation == HORIZONTAL)
- htextOffset = -halfWidth;
- else
- htextOffset = bounds.size.width/2-halfWidth;
- }
- if (orientation == HORIZONTAL) {
- if (inverted)
- vtextOffset = TEXTBASELINE;
- else
- vtextOffset = bounds.size.height - lineHeight;
- if (vtextOffset < TEXTBASELINE)
- vtextOffset = TEXTBASELINE;
- PSmoveto(j*scaleSpacing+leftOrBottomMargin+htextOffset+border, vtextOffset);
- }
- else
- PSmoveto(htextOffset, j*scaleSpacing+leftOrBottomMargin-(lineHeight/2)+border);
- if (j>=0)
- PSshow(buf);
- }
-
- return self;
- }
-
- /* Event handling */
- - (BOOL) acceptsFirstMouse
- {
- return YES;
- }
-
- - mouseDown:(NXEvent *)theEvent
- {
- id rulerWindow;
- int oldMask, looping = YES;
- NXRect windowRect,tempRect,visibleRect;
- NXPoint offset, mouseLocation;
- BOOL shiftHeld = NO;
-
- if (!draggableRuler)
- return self;
- if (theEvent->flags & NX_SHIFTMASK) shiftHeld = YES;
-
- // if(theEvent->data.mouse.click == 2)
- /* action for a double-click event */
-
- /* convert the visible rect to screen-based coordinates */
- [self getVisibleRect:(NXRect *)&windowRect];
- [self convertRect:&windowRect toView:nil];
- [window convertBaseToScreen:&windowRect.origin];
-
- /* adjust for width of outline */
- windowRect.size.width += 2;
- windowRect.size.height += 2;
- windowRect.origin.x -= 1;
- windowRect.origin.y -= 1;
- tempRect.size = windowRect.size;
- tempRect.origin = bounds.origin;
-
- rulerWindow = [[Window alloc] initContent:(const NXRect *)&windowRect
- style:(int)NX_PLAINSTYLE // no title bar and frame
- backing:(int)NX_BUFFERED
- buttonMask:(int)0 // no controls in title bar and frame
- defer:(BOOL)NO];
-
- /* so we can draw the currently visible region */
- [self getVisibleRect:&visibleRect];
-
- /* draw the ruler into the newly created window's content view */
- [[rulerWindow contentView] lockFocus];
- // account for frame and translate to currently visible region
- PStranslate(1-visibleRect.origin.x,1-visibleRect.origin.y);
- [self drawSelf:&bounds:0];
- PStranslate(-1+visibleRect.origin.x,-1+visibleRect.origin.y);
- NXFrameRect((const NXRect *)&tempRect);
- [[rulerWindow contentView] unlockFocus];
-
- [rulerWindow orderFront:NULL];
-
- /* compute the offset from the image's origin to the mouse location */
- offset.x = theEvent->location.x - NX_X(&windowRect)+2;
- offset.y = theEvent->location.y - NX_Y(&windowRect)-2;
-
- /* convert the mousedown location to screen coordinates */
- mouseLocation = theEvent->location;
- [window convertBaseToScreen:&mouseLocation];
-
- /* go into the dragging loop */
- oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
- while(looping) {
- theEvent = [NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK];
- if(theEvent->type == NX_MOUSEDRAGGED){
- if (shiftHeld == YES) { // constrain drag
- [rulerWindow getFrame:&tempRect];
- if (orientation == HORIZONTAL)
- [rulerWindow moveTo:tempRect.origin.x
- :theEvent->location.y-offset.y];
- else
- [rulerWindow moveTo:theEvent->location.x-offset.x
- :tempRect.origin.y];
- }
- else
- [rulerWindow moveTo:theEvent->location.x-offset.x
- :theEvent->location.y-offset.y];
- }
- else { /* NX_MOUSEUP */
- [rulerWindow free];
- looping = NO;
- }
- }
-
- return self;
- }
-
- /* Sizing the rulers */
- - setSize
- // Sets the size of the view. Invoked by the setSize method of
- // RuledScrollView, which must be invoked whenever the size of
- // the mainView is changed.
- // In addition to sizing the ruler, this method also sets the instance
- // variables leftOrBottomMargin and rightOrTopMargin, which determine
- // the location of the origin of the ruler. If the ruler extends over
- // the end of an adjacent ruler, the corresponding margin is set to
- // the width or height of that ruler. (In order to extend over the
- // end of another ruler, the ruler must be a 'primary' ruler and
- // there must be no corresponding stubView.) The intention of the
- // margin variables is to locate the origin of the ruler at the
- // edge of the view that it 'rules', automatically accounting
- // for whatever stub views exist and which rulers are primary.
- //
- // For example, sizing a Right Ruler is done as follows:
- // 1) if Vertical Rulers are primary, and there is a bottom ruler
- // and there isn't a bottom right stubView, set
- // leftOrBottomMargin to the height of the bottom ruler
- // 2) if Vertical Rulers are primary, and there is a top ruler
- // and there isn't a top right stubView, set
- // rightOrTopMargin to the height of the top ruler
- // 4) the height is set to the height of the main View +
- // leftOrBottomMargin + rightOrTopMargin. The width is
- // unchanged.
-
- {
- NXRect theRect, mainViewFrame, rulerFrame;
- id leftOrBottomRuler, rightOrTopRuler, ruledScrollView, stub;
-
- /* Ruler's super is a clipview; it's super is RuledScrollView,
- * it's docView is the main View */
- ruledScrollView = [superview superview];
- if (![ruledScrollView isKindOf:[RuledScrollView class]])
- // this ruler is not currently in a RuledScrollView
- // (probably because ruler is hidden)
- return self;
- [[ruledScrollView docView] getFrame:&mainViewFrame];
- [self getFrame:(NXRect *)&theRect];
- leftOrBottomMargin = 0.0;
- rightOrTopMargin = 0.0;
- if (orientation == HORIZONTAL) {
- leftOrBottomRuler = [ruledScrollView leftRuler];
- if ([ruledScrollView bottomRuler] == self)
- stub = [ruledScrollView bottomLeftStub];
- else
- stub = [ruledScrollView topLeftStub];
- if (leftOrBottomRuler && (!stub) && ([ruledScrollView primaryRulers] == TOPBOTTOM)) {
- [leftOrBottomRuler getFrame:&rulerFrame];
- leftOrBottomMargin = rulerFrame.size.width;
- }
-
- rightOrTopRuler = [ruledScrollView rightRuler];
- if ([ruledScrollView bottomRuler] == self)
- stub = [ruledScrollView bottomRightStub];
- else
- stub = [ruledScrollView topRightStub];
- if (rightOrTopRuler && (!stub) && ([ruledScrollView primaryRulers] == TOPBOTTOM)) {
- [rightOrTopRuler getFrame:&rulerFrame];
- rightOrTopMargin = rulerFrame.size.width;
- }
- theRect.size.width = mainViewFrame.size.width
- + leftOrBottomMargin + rightOrTopMargin;
- }
- else {
- leftOrBottomRuler = [ruledScrollView bottomRuler];
- if ([ruledScrollView leftRuler] == self)
- stub = [ruledScrollView bottomLeftStub];
- else
- stub = [ruledScrollView bottomRightStub];
- if ((leftOrBottomRuler) && (!stub) && ([ruledScrollView primaryRulers] == LEFTRIGHT)) {
- [leftOrBottomRuler getFrame:&rulerFrame];
- leftOrBottomMargin = rulerFrame.size.height;
- }
-
- rightOrTopRuler = [ruledScrollView topRuler];
- if ([ruledScrollView leftRuler] == self)
- stub = [ruledScrollView topLeftStub];
- else
- stub = [ruledScrollView topRightStub];
- if ((rightOrTopRuler) && (!stub) && ([ruledScrollView primaryRulers] == LEFTRIGHT)) {
- [rightOrTopRuler getFrame:&rulerFrame];
- rightOrTopMargin = rulerFrame.size.height;
- }
- theRect.size.height = mainViewFrame.size.height
- + leftOrBottomMargin + rightOrTopMargin;
- }
- [self setFrame:(NXRect *)&theRect];
- return self;
- }
-
- /* Setting/returning Ruler attributes */
- - setScaleSpacing:(NXCoord)points
- {
- scaleSpacing = points;
- return self;
- }
-
- - (NXCoord)scaleSpacing { return scaleSpacing; }
-
- - setScale:(float)scaleIncrement
- // the increment of the scale reading between major marks
- {
- scale = scaleIncrement;
- return self;
- }
-
- - (float)scale { return scale; }
-
- - setScaleOffset:(float)origin
- {
- scaleOffset = origin;
- return self;
- }
-
- - (float)scaleOffset { return scaleOffset; }
-
- - setBorder:(NXCoord)theBorder
- {
- border = theBorder;
- return self;
- }
-
- - (NXCoord)border { return border; }
-
- - setOrientation:(float)angle
- // set to the manifest HORIZONTAL or VERTICAL
- // must be set before sending setSize:
- {
- orientation = angle;
- return self;
- }
-
- - (float)orientation { return orientation; }
-
- - setInverted:(BOOL)invertFlag
- // a flag that may be checked in drawself: to draw a
- // ruler reflected vertically top or right side
- {
- inverted = invertFlag;
- return self;
- }
-
- - (BOOL)inverted { return inverted; }
-
- - setMirrored:(BOOL)mirrorFlag
- // a flag that may be checked in drawself: to draw a
- // the ruler reflected horizontally
- {
- mirrored = mirrorFlag;
- return self;
- }
-
- - (BOOL)mirrored { return mirrored; }
-
- - setAlignment:(int)alignType
- // set to one of NX_LEFTALIGNED, NX_CENTERED, NX_RIGHTALIGNED
- // manifests defined in appkit/Text.h
- {
- alignment = alignType;
- return self;
- }
-
- - (int)alignment { return alignment; }
-
- - setUnits:(char *)name
- {
- if (name == NULL) return self;
- if (strlen(units) < strlen(name)) {
- free(units);
- units = malloc(strlen(name)*sizeof(char));
- }
- strcpy(units,name);
- return self;
- }
-
- - (const char *)units {return (const char *)units;}
-
- - setFont:aFont
- {
-
- font = aFont;
- NXTextFontInfo(font, &ascender, &descender, &lineHeight);
- if (descender < 0.0) descender = -1.0 * descender;
-
- return self;
- }
-
- - (Font *)font { return font; }
-
- - setBackgroundColor:(NXColor)bColor
- {
- backgroundColor = bColor;
- return self;
- }
-
- - (NXColor)backgroundColor {return backgroundColor;}
-
- - setBackgroundGray:(float)value;
- {
- backgroundGray = value;
- return self;
- }
-
- - (float)backgroundGray{return backgroundGray;}
-
- - setImage:anImage
- {
- /* an image object for rulers that tile an image to the background */
- image = anImage;
- return self;
- }
-
- - image
- {
- return image;
- }
-
- - setDraggableRuler:(BOOL)yesOrNo;
- {
- draggableRuler = yesOrNo;
- return self;
- }
-
- - (BOOL)draggableRuler {return draggableRuler; }
-
- @end
-