This is MoveMatrix.m in view mode; [Download] [Up]
/* Generated by Interface Builder */
#import "MoveMatrix.h"
#import "MyCell.h"
#import <appkit/Cell.h>
#import <appkit/TextFieldCell.h>
#import <appkit/SelectionCell.h>
#import <appkit/MenuCell.h>
#import <appkit/defaults.h>
#import <appkit/nextstd.h>
#import <appkit/tiff.h>
#import <appkit/timer.h>
#import <dpsclient/wraps.h>
@implementation MoveMatrix
- initFrame: (const NXRect *) frameRect
{
[self setCellClass:[ButtonCell class]];
self = [super initFrame: frameRect];
[self setBackgroundGray:0.5];
return self;
}
- initFrame: (const NXRect *) frameRect mode: (int) mode prototype: anObject
numRows: (int) nRows numCols: (int) nCols
{
self = [super initFrame: frameRect mode: mode prototype: anObject
numRows: nRows numCols: nCols];
return self;
}
// MoveMatrix delegate.
// The delegate should prepare following methods:
// - matrixDidExchange: (int) index1 : (int) index2
//
- setMoveDelegate: anObject
{
moveDelegate = anObject;
}
- moveDelegate
{
return moveDelegate;
}
- mouseDown:(NXEvent *) event
{
BOOL gotHit;
int oldMask;
oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK|NX_MOUSEUPMASK];
gotHit = [self move:event];
[window setEventMask:oldMask];
if (!gotHit) {
[super mouseDown: event];
}
return self;
}
- selectionCache
/*
* Shares an off-screen window used to draw the selection in so that it
* can be dragged around. If the current off-screen window is equal in
* size or larger than the passed size, then it is simply returned.
* Otherwise, it is resized to be the specified size.
*/
{
NXRect rect;
static id selectioncache = nil;
NXRect defaultRect = {{0.0, 0.0}, {300.0, 300.0}};
if (!selectioncache) {
rect = defaultRect;
selectioncache = [[Window alloc] initContent:&rect
style:NX_PLAINSTYLE
backing:NX_RETAINED
buttonMask:0
defer:NO];
[selectioncache reenableDisplay];
} else {
[selectioncache getFrame:&rect];
if (rect.size.width < bounds.size.width ||
rect.size.height < bounds.size.height) {
[selectioncache sizeWindow:MAX(rect.size.width, bounds.size.width)
:MAX(rect.size.height, bounds.size.height)];
}
}
return selectioncache;
}
-(int)cacheCell:aCell in:(NXRect *)sbounds inView:aView
{
int i;
id selectionCache;
if (!aView) aView = self;
selectionCache = [aView selectionCache];
[[selectionCache contentView] lockFocus];
PSsetgray(NX_WHITE);
PSsetalpha(0.0); /* fully transparent */
PStranslate(- NX_X(sbounds), - NX_Y(sbounds));
NX_WIDTH(sbounds) += 1.0;
NX_HEIGHT(sbounds) += 1.0;
NXRectFill(sbounds);
NX_WIDTH(sbounds) -= 1.0;
NX_HEIGHT(sbounds) -= 1.0;
PSsetalpha(1.0); /* fully opaque */
[aCell drawSelf:sbounds inView:[selectionCache contentView]];
PStranslate(NX_X(sbounds), NX_Y(sbounds));
[[selectionCache contentView] unlockFocus];
return [selectionCache gState];
}
- compositeSelection:(const NXRect *)sbounds from:(int)gstate
/*
* Composites from the specified gstate whatever part of sbounds is
* currently visible in the View.
*/
{
//y position modified to work with a flipped destination view
PScomposite(0.0, 0.0, NX_WIDTH(sbounds), NX_HEIGHT(sbounds),
gstate, NX_X(sbounds), NX_Y(sbounds)+NX_HEIGHT(sbounds), NX_SOVER);
[window flushWindow];
NXPing();
return self;
}
#define stopTimer(timer) if (timer) { \
NXEndTimer(timer); \
timer = NULL; \
}
#define startTimer(timer) if (!timer) timer = NXBeginTimer(NULL, 0.1, 0.1);
#define MOVE_MASK NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK
- (BOOL) move: (NXEvent *) event
{
int gstate;
int row, col;
static int originalRow, originalCol;
static id aCell;
NXCoord dx, dy;
NXEvent peek;
NXPoint p, last, center;
NXRect sbounds, visibleRect, cellFrame;
NXTrackingTimer *timer = NULL;
BOOL canScroll, tracking = YES;
static MyCell *substituteCell = nil;
if (!substituteCell) substituteCell = [MyCell new];
last = event->location;
[self convertPoint:&last fromView:nil];
[self lockFocus];
//unhighlight previously highlit cell (aCell is static and is saved from
//last entry into method
if (aCell == nil) {
// [self highlightCellAt:originalRow:originalCol lit:NO];
} else {
[self getRow:&row andCol:&col ofCell:aCell];
// [self highlightCellAt:row:col lit:NO];
}
//highlight cell clicked on
[self getRow:&originalRow andCol:&originalCol forPoint:&last];
// [self highlightCellAt:originalRow:originalCol lit:YES];
event = [NXApp getNextEvent:MOVE_MASK];
if (event->type == NX_MOUSEUP) {
aCell = nil;
[self unlockFocus];
return NO;
}
// cache the image of the selected cell
[self getCellFrame:&sbounds at:originalRow:originalCol];
aCell = [self cellAt:originalRow:originalCol];
gstate = [self cacheCell:aCell in:&sbounds inView: self];
[self compositeSelection:&sbounds from:gstate];
[self putCell:substituteCell at:originalRow:originalCol];
[self getVisibleRect:&visibleRect];
canScroll = !NXEqualRect(&visibleRect, &bounds);
while (tracking) {
p = event->location;
[self convertPoint:&p fromView:nil];
// only moving in horizontal direction
dx = p.x - last.x;
if (dx) {
[self drawSelf:&sbounds :1];
NXOffsetRect(&sbounds, dx, 0.0);
//set up so cell image stays within matrix bounds
if (!canScroll ||
(visibleRect.origin.x == 0.0) ||
((visibleRect.origin.x + visibleRect.size.width)==bounds.size.width))
{
//assuming a flipped view
//lefthand of the matrix
if (sbounds.origin.x < bounds.origin.x) {
p.x += bounds.origin.x - sbounds.origin.x;
sbounds.origin.x = bounds.origin.x;
} else if ((sbounds.origin.x + sbounds.size.width) >
(bounds.origin.x + bounds.size.width)) {
//righthand of the matrix
p.x -= sbounds.origin.x - ((bounds.origin.x + bounds.size.width)
- sbounds.size.width);
sbounds.origin.x = (bounds.origin.x + bounds.size.width)
- sbounds.size.width + 1;
}
}
if (!canScroll || NXContainsRect(&visibleRect, &sbounds)) {
[self compositeSelection:&sbounds from:gstate];
stopTimer(timer);
}
last = p;
}
tracking = (event->type != NX_MOUSEUP);
if (tracking) {
if (canScroll && !NXContainsRect(&visibleRect, &sbounds)) {
[window disableFlushWindow];
[self scrollRectToVisible:&sbounds];
[self getVisibleRect:&visibleRect];
[self compositeSelection:&sbounds from:gstate];
[[window reenableFlushWindow] flushWindow];
startTimer(timer);
}
p = event->location;
if (![NXApp peekNextEvent:MOVE_MASK into:&peek]) {
event = [NXApp getNextEvent:MOVE_MASK|NX_TIMERMASK];
} else {
event = [NXApp getNextEvent:MOVE_MASK];
}
if (event->type == NX_TIMER) event->location = p;
}
}
if (canScroll) stopTimer(timer);
//set up p so that the y dimension isn't affecting inclusion in matrix
p.y = 0.0;
center.x = sbounds.origin.x + sbounds.size.width / 2.0;
center.y = 0.0;
// make sure we're dealing with a valid column
if (![self getRow:&row andCol:&col forPoint:¢er]) {
row = 0;
if (center.x < 0) col = 0;
else col = [self cellCount]-1;
}
[self drawSelf: &sbounds :1];
//whole bunch of finetuning to get this to look right
if (col == originalCol) {
[self putCell: aCell at: row : col];
[super selectCellAt: row : col];
[super sendAction];
} else {
aCell = [self putCell: aCell at: row : col];
[self putCell: aCell at: originalRow : originalCol];
if (moveDelegate) {
[moveDelegate matrixDidExchange: originalCol : col];
}
}
[self display];
[window flushWindow];
[self unlockFocus];
return YES;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.