|
|
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.