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;
}
@endThese are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.