|
|
1.1 ! root 1: ! 2: /* SortView is a custom view class that displays a graphically animating sort. ! 3: * Each sort creates a SortView to manage its display. The SortView will draw ! 4: * the necessary animation when a sort is moving or comparing elements. ! 5: * ! 6: * Author: Julie Zelenski, NeXT Developer Support ! 7: * You may freely copy, distribute and reuse the code in this example. ! 8: * NeXT disclaims any warranty of any kind, expressed or implied, as to ! 9: * its fitness for any particular use. ! 10: */ ! 11: ! 12: ! 13: #import "SortView.h" ! 14: #import "GenericSort.h" ! 15: #import "SortApp.h" ! 16: #import <appkit/Font.h> ! 17: #import <appkit/nextstd.h> ! 18: #import <dpsclient/wraps.h> ! 19: #import <math.h> ! 20: #import "SortWraps.h" ! 21: ! 22: extern BOOL Abort; // global variable to signal abort ! 23: ! 24: ! 25: @implementation SortView:View ! 26: ! 27: ! 28: - initSort:aSort ! 29: /* Each sort will create a new SortView for itself by calling initSort. ! 30: * This init method sets a default size view, sets up a few instance ! 31: * variables, grabs a few fonts and strings to be used later. It also ! 32: * allocates a gState for itself to improve performance, because the ! 33: * sortviews are repeatedly lockFocus'ed on. ! 34: */ ! 35: { ! 36: #define HORIZ_MARGIN 3.0 ! 37: #define VERT_MARGIN 13.0 ! 38: ! 39: NXRect frameRect = {{2.0,2.0},{VIEW_WIDTH,VIEW_HEIGHT}}; ! 40: ! 41: [self initFrame:&frameRect]; ! 42: sort = aSort; ! 43: drawRect.size.width = bounds.size.width - 2*HORIZ_MARGIN; ! 44: drawRect.size.height = bounds.size.height - VERT_MARGIN; ! 45: drawRect.origin.x = bounds.origin.x + HORIZ_MARGIN; ! 46: drawRect.origin.y = bounds.origin.y; ! 47: numRows = 1; ! 48: numPixelsInRow = drawRect.size.width; ! 49: elementWidth = barWidth = 1.0; ! 50: rowHeight = drawRect.size.height; ! 51: numberFont = [Font newFont:"Helvetica" size:24 matrix:NX_IDENTITYMATRIX]; ! 52: titleFont = [Font newFont:"Helvetica" size:12 matrix:NX_IDENTITYMATRIX]; ! 53: [self setClipping:NO]; // I won't draw outside my bounds so don't clip ! 54: [self allocateGState]; // gstate will decrease lock/unlock focus time ! 55: return self; ! 56: } ! 57: ! 58: ! 59: - setUpForSize:(int)numElements; ! 60: /* This method is called by the sort when it knows how many elements are in ! 61: * the current data set. It will calculates the rowHeight and barWidth ! 62: * that will allow all the elements to fit. When there is a smaller data set, ! 63: * the bars are wider and there is a gap between bars. With larger data sets, ! 64: * the sortView will layer the elements in more than one row ! 65: */ ! 66: { ! 67: numRows = 1; ! 68: elementWidth = barWidth = floor(drawRect.size.width/numElements); ! 69: switch (barWidth) { ! 70: case 0: numRows = ceil((float)numElements/numPixelsInRow); ! 71: barWidth = 1.0; ! 72: elementWidth = 1.0; ! 73: break; ! 74: case 1: break; ! 75: case 2: barWidth -= 1.0; ! 76: break; ! 77: default: barWidth -= 2.0; ! 78: break; ! 79: } ! 80: rowHeight = floor(drawRect.size.height/(float)numRows); ! 81: return self; ! 82: } ! 83: ! 84: ! 85: - compare:(int)element1 value:(int)value1 with:(int)element2 value:(int)value2 ! 86: /* This method is called to show two values are being compared. The ! 87: * comparison is shown by highlighting the two bars in light gray. This ! 88: * highlighting is done with instance drawing, because I want it to be ! 89: * transitory. At each drawing request, the sortView will hide any previous ! 90: * instance drawing. This way I never have to erase the comparisons. They ! 91: * will be "flushed" away in the next drawing. ! 92: * PSWcompareRects is a wrap which simply turns on instance drawing, sets ! 93: * the gray, fills the two rectangles in gray and turns off instance drawing. ! 94: */ ! 95: { ! 96: NXPoint pt1,pt2; ! 97: ! 98: [self lockFocus]; ! 99: pt1.x = drawRect.origin.x + (element1%numPixelsInRow)*elementWidth; ! 100: pt1.y = (numRows - (element1/numPixelsInRow)-1)*rowHeight; ! 101: pt2.x = drawRect.origin.x + (element2%numPixelsInRow)*elementWidth; ! 102: pt2.y = (numRows - (element2/numPixelsInRow)-1)*rowHeight; ! 103: PShideinstance(0.0,0.0,bounds.size.width,bounds.size.height); ! 104: PSWcompareRects(pt1.x,pt1.y,barWidth,value1,pt2.x,pt2.y,value2); ! 105: [self unlockFocus]; ! 106: return self; ! 107: } ! 108: ! 109: ! 110: - swap:(int)element1 value:(int)value1 with:(int)element2 value:(int)value2 ! 111: /* This method is called to swap two elements. It draws only the changed ! 112: * parts: it adds height to the smaller bar (by drawing in black) and removes ! 113: * height from the larger bar (by drawing in white). ! 114: * PSWswapRects is a wrap which sets the gray to white, fills the white ! 115: * rectangle, sets the gray to black, fills the black rectangle, and flushes ! 116: * the drawing to the screen immediately. ! 117: */ ! 118: { ! 119: NXPoint pt1,pt2; ! 120: ! 121: if ((value1 != value2) && !Abort) { // if values actually need to change ! 122: [self lockFocus]; ! 123: pt1.x = drawRect.origin.x + (element1%numPixelsInRow)*elementWidth; ! 124: pt1.y = value1 + (numRows - (element1/numPixelsInRow)-1)*rowHeight; ! 125: pt2.x = drawRect.origin.x + (element2%numPixelsInRow)*elementWidth; ! 126: pt2.y = value1 + (numRows - (element2/numPixelsInRow)-1)*rowHeight; ! 127: PShideinstance(0.0,0.0,bounds.size.width,bounds.size.height); ! 128: PSWswapRects(pt1.x,pt1.y,pt2.x,pt2.y,barWidth,value2-value1); ! 129: [self unlockFocus]; ! 130: } ! 131: return self; ! 132: } ! 133: ! 134: ! 135: - moveValue:(int)new to:(int)element oldValue:(int)old ! 136: /* This method is called to change the value of an element. It draws only the ! 137: * changed part: it adds height (draws in black) if the value increased, or ! 138: * it removes height (draws in white) if the value decreased. ! 139: * PSWmoveRects is a wrap which sets the gray appropriately, fills the ! 140: * rectangle, and flushes the drawing to the screen immediately. ! 141: */ ! 142: { ! 143: NXPoint p; ! 144: ! 145: if ((new != old) && !Abort) { // if value actually needs to change ! 146: [self lockFocus]; ! 147: p.x = drawRect.origin.x + (element%numPixelsInRow)*elementWidth; ! 148: p.y = MIN(old,new) + (numRows - (element/numPixelsInRow)-1)*rowHeight; ! 149: PShideinstance(0.0,0.0,bounds.size.width,bounds.size.height); ! 150: PSWmoveRect(p.x,p.y,barWidth,ABS(old-new),((new>old)?NX_BLACK:NX_WHITE)); ! 151: [self unlockFocus]; ! 152: } ! 153: return self; ! 154: } ! 155: ! 156: ! 157: - drawSelf:(const NXRect *)rects :(int)rectCount; ! 158: /* In drawSelf, the sortView simple erases its background, draws the border and ! 159: * labels itself with the appropriate name. ! 160: */ ! 161: { ! 162: NXEraseRect(&bounds); ! 163: PSWdrawBorder(bounds.size.width,bounds.size.height); ! 164: [titleFont set]; ! 165: PSWdrawName(drawRect.origin.x,drawRect.size.height,(char *)[sort getName]); ! 166: return self; ! 167: } ! 168: ! 169: ! 170: - drawStatistics; ! 171: /* This methods displays the statistics when a sort finishes. It fades the ! 172: * sort background, and queries the sort for the necessary numbers to display ! 173: * and title. It looks up the strings for the titles in the SortApp's ! 174: * NXStringTable. ! 175: */ ! 176: { ! 177: char a[9],b[9],c[9],d[9]; ! 178: id sTable; ! 179: ! 180: sprintf(a,"%8d",[sort totalTicks]); ! 181: sprintf(b,"%8d",[sort compares]); ! 182: sprintf(c,"%8d",[sort moves]); ! 183: sprintf(d,"%8d",[sort fcalls]); ! 184: [numberFont set]; ! 185: PSWdrawStrings(a,b,c,d,35.0); ! 186: [titleFont set]; ! 187: if (!tickString) { ! 188: sTable = [NXApp stringTable]; ! 189: tickString = NXCopyStringBuffer([sTable valueForStringKey:"Ticks"]); ! 190: moveString = NXCopyStringBuffer([sTable valueForStringKey:"Moves"]); ! 191: compString = NXCopyStringBuffer([sTable valueForStringKey:"Compares"]); ! 192: fcallString = NXCopyStringBuffer([sTable valueForStringKey:"Fcalls"]); ! 193: } ! 194: PSWdrawStrings(tickString, compString, moveString, fcallString, 65.0); ! 195: return self; ! 196: } ! 197: ! 198: - displayFinished; ! 199: /* This methods displays a sort when it finishes. It fades the sort ! 200: * background, and if the sort finished normally (i.e. it wasn't canceled), ! 201: * it will call a method to display the sort's statistics. ! 202: */ ! 203: { ! 204: [self lockFocus]; ! 205: PSWfade(bounds.size.width,bounds.size.height); ! 206: PSWdrawBorder(bounds.size.width,bounds.size.height); ! 207: [titleFont set]; ! 208: PSWdrawName(drawRect.origin.x,drawRect.size.height,(char *)[sort getName]); ! 209: if (!Abort) ! 210: [self drawStatistics]; ! 211: [self unlockFocus]; ! 212: [window flushWindow]; ! 213: return self; ! 214: } ! 215: ! 216: ! 217: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.