This is OrderMatrix.m in view mode; [Download] [Up]
#import <dpsclient/psops.h> #import <dpsclient/wraps.h> #import <appkit/timer.h> #import <appkit/Cell.h> #import <appkit/Window.h> #import <appkit/Application.h> #import <appkit/publicWraps.h> #import "OrderMatrix.h" @implementation OrderMatrix #define startTimer(timer)\ if (!timer) timer = NXBeginTimer(NULL, 0.1, 0.01); #define stopTimer(timer) if (timer) { \ NXEndTimer(timer); \ timer = NULL; \ } #define MOVE_MASK NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK /* instance methods */ - (BOOL) acceptsFirstResponder { return YES; } - free { [matrixCache free]; [cellCache free]; return [super free]; } - delete:sender { int row = [self selectedRow]; if (row >= 0) { [self removeRowAt:row andFree:YES]; [self sizeToCells]; [[self superview] display]; if (![textDelegate textWillChange:self]) [textDelegate textDidChange:self]; } else NXBeep(); return self; } - keyDown:(NXEvent *)theEvent { if (theEvent->data.key.charCode == 127) { int row = [self selectedRow]; if (row >= 0) { [self removeRowAt:row andFree:YES]; [self sizeToCells]; [[self superview] display]; if (![textDelegate textWillChange:self]) [textDelegate textDidChange:self]; } else NXBeep(); return self; } else return [super keyDown:theEvent]; } - mouseDown:(NXEvent *)theEvent { NXPoint mouseDownLocation, mouseUpLocation, mouseLocation; int eventMask, row, column, newRow; NXRect visibleRect, cellCacheBounds, cellFrame; id matrixCacheContentView, cellCacheContentView; float dy; NXEvent *event, peek; NXTrackingTimer *timer = NULL; BOOL scrolled = NO; theEvent->flags = 0; /* peek on the next event. If it is a mouse up, let super do the work */ eventMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK]; if ([NXApp peekNextEvent:MOVE_MASK into:&peek waitFor:0.25 threshold:NX_BASETHRESHOLD]) { if (peek.type == NX_MOUSEUP) { [window setEventMask:eventMask]; return [super mouseDown:theEvent]; } } /* prepare the cell and matrix cache windows */ [window disableFlushWindow]; [self setupCacheWindows]; /* find the cell that got clicked on and select it */ mouseDownLocation = theEvent->location; [self convertPoint:&mouseDownLocation fromView:nil]; [self getRow:&row andCol:&column forPoint:&mouseDownLocation]; activeCell = [self cellAt:row :column]; [self selectCell:activeCell]; [self getCellFrame:&cellFrame at:row :column]; /* do whatever's required for a single-click */ [self sendAction]; /* draw a "well" in place of the selected cell (see drawSelf::) */ [self display:&cellFrame :1]; /* copy what's currently visible into the matrix cache */ matrixCacheContentView = [matrixCache contentView]; [matrixCacheContentView lockFocus]; [self getVisibleRect:&visibleRect]; [self convertRect:&visibleRect toView:nil]; PScomposite(NX_X(&visibleRect), NX_Y(&visibleRect), NX_WIDTH(&visibleRect), NX_HEIGHT(&visibleRect), [window gState], 0.0, NX_HEIGHT(&visibleRect), NX_COPY); [matrixCacheContentView unlockFocus]; /* image the cell into its cache */ cellCacheContentView = [cellCache contentView]; [cellCacheContentView lockFocus]; [cellCacheContentView getBounds:&cellCacheBounds]; NXSetColor(NX_COLORLTGRAY); NXRectFill(&cellCacheBounds); [activeCell drawSelf:&cellCacheBounds inView:cellCacheContentView]; [cellCacheContentView unlockFocus]; /* save the mouse's location relative to the cell's origin */ dy = mouseDownLocation.y - cellFrame.origin.y; [window reenableFlushWindow]; /* from now on we'll be drawing into ourself */ [self lockFocus]; event = theEvent; while (event->type != NX_MOUSEUP) { /* erase the active cell using the image in the matrix cache */ [self getVisibleRect:&visibleRect]; PScomposite(NX_X(&cellFrame), NX_HEIGHT(&visibleRect) - NX_Y(&cellFrame) + NX_Y(&visibleRect) - NX_HEIGHT(&cellFrame), NX_WIDTH(&cellFrame), NX_HEIGHT(&cellFrame), [matrixCache gState], NX_X(&cellFrame), NX_Y(&cellFrame) + NX_HEIGHT(&cellFrame), NX_COPY); /* move the active cell */ mouseLocation = event->location; [self convertPoint:&mouseLocation fromView:nil]; cellFrame.origin.y = mouseLocation.y - dy; /* constrain the cell's location to our bounds */ if (NX_Y(&cellFrame) < NX_X(&bounds) ) { cellFrame.origin.y = NX_X(&bounds); } else if (NX_MAXY(&cellFrame) > NX_MAXY(&bounds)) { cellFrame.origin.y = NX_HEIGHT(&bounds) - NX_HEIGHT(&cellFrame); } /* * make sure the cell will be entirely visible in its new location (if * we're in a scrollView, it may not be) */ if (!NXContainsRect(&visibleRect, &cellFrame) && mFlags.autoscroll) { /* * the cell won't be entirely visible, so scroll, dood, scroll, but * don't display on-screen yet */ [window disableFlushWindow]; [self scrollRectToVisible:&cellFrame]; [window reenableFlushWindow]; /* copy the new image to the matrix cache */ [matrixCacheContentView lockFocus]; [self getVisibleRect:&visibleRect]; [self convertRectFromSuperview:&visibleRect]; [self convertRect:&visibleRect toView:nil]; PScomposite(NX_X(&visibleRect), NX_Y(&visibleRect), NX_WIDTH(&visibleRect), NX_HEIGHT(&visibleRect), [window gState], 0.0, NX_HEIGHT(&visibleRect), NX_COPY); [matrixCacheContentView unlockFocus]; /* * note that we scrolled and start generating timer events for * autoscrolling */ scrolled = YES; startTimer(timer); } else { /* no scrolling, so stop any timer */ stopTimer(timer); } /* composite the active cell's image on top of ourself */ PScomposite(0.0, 0.0, NX_WIDTH(&cellFrame), NX_HEIGHT(&cellFrame), [cellCache gState], NX_X(&cellFrame), NX_Y(&cellFrame) + NX_HEIGHT(&cellFrame), NX_COPY); /* now show what we've done */ [window flushWindow]; /* * if we autoscrolled, flush any lingering window server events to make * the scrolling smooth */ if (scrolled) { NXPing(); scrolled = NO; } /* save the current mouse location, just in case we need it again */ mouseLocation = event->location; if (![NXApp peekNextEvent:MOVE_MASK into:&peek]) { event = [NXApp getNextEvent:MOVE_MASK|NX_TIMERMASK]; } else { event = [NXApp getNextEvent:MOVE_MASK]; } /* if a timer event, mouse location isn't valid, so we'll set it */ if (event->type == NX_TIMER) { event->location = mouseLocation; } } /* mouseUp, so stop any timer and unlock focus */ stopTimer(timer); [self unlockFocus]; /* find the cell under the mouse's location */ mouseUpLocation = event->location; [self convertPoint:&mouseUpLocation fromView:nil]; if (![self getRow:&newRow andCol:&column forPoint:&mouseUpLocation]) { /* mouse is out of bounds, so find the cell the active cell covers */ [self getRow:&newRow andCol:&column forPoint:&(cellFrame.origin)]; } /* we need to shuffle cells if the active cell's going to a new location */ if (newRow != row) { [self setAutodisplay:NO]; if (newRow > row) { if (selectedRow <= newRow) selectedRow--; while (row++ < newRow) { cell = [self cellAt:row :0]; [self putCell:cell at:(row - 1) :0]; } [self putCell:activeCell at:newRow :0]; } else if (newRow < row) { if (selectedRow >= newRow) selectedRow++; while (row-- > newRow) { cell = [self cellAt:row :0]; [self putCell:cell at:(row + 1) :0]; } [self putCell:activeCell at:newRow :0]; } if ([activeCell state]) { selectedRow = newRow; } /* make sure the active cell's visible if we're autoscrolling */ if (mFlags.autoscroll) { [self scrollCellToVisible:newRow :0]; } activeCell = 0; [[self sizeToCells] setAutodisplay:YES]; } else { activeCell = 0; } [self display]; [window setEventMask:eventMask]; if (![textDelegate textWillChange:self]) [textDelegate textDidChange:self]; return self; } - drawSelf:(NXRect *)rects :(int)count { int row, col; NXRect cellBorder; [super drawSelf:rects :count]; if (activeCell) { [self getRow:&row andCol:&col ofCell:activeCell]; [self getCellFrame:&cellBorder at:row :col]; if (NXIntersectsRect(&cellBorder, &(rects[0]))) { PSsetgray(0.5); NXRectFill(&cellBorder); } } return self; } - setupCacheWindows { NXRect visibleRect; /* create the matrix cache window */ [self getVisibleRect:&visibleRect]; matrixCache = [self sizeCacheWindow:matrixCache to:&(visibleRect.size)]; /* create the cell cache window */ cellCache = [self sizeCacheWindow:cellCache to:&cellSize]; return self; } - sizeCacheWindow:cacheWindow to:(NXSize *)windowSize { NXRect cacheFrame; if (!cacheWindow) { cacheFrame.origin.x = cacheFrame.origin.y = 0.0; cacheFrame.size = *windowSize; cacheWindow = [[[Window alloc] initContent:&cacheFrame style:NX_PLAINSTYLE backing:NX_RETAINED buttonMask:0 defer:NO] reenableDisplay]; [[cacheWindow contentView] setFlipped:YES]; } else { [cacheWindow getFrame:&cacheFrame]; if (cacheFrame.size.width != windowSize->width || cacheFrame.size.height != windowSize->height) { [cacheWindow sizeWindow:windowSize->width :windowSize->height]; } } return cacheWindow; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.