This is SlidingMatrix.m in view mode; [Download] [Up]
/*-------------------------------------------------------------------------- * * You may freely copy, distribute, and reuse the code in this example. * SHL Systemhouse disclaims any warranty of any kind, expressed or * implied, as to its fitness for any particular use. * * * SlidingMatrix * * Inherits From: Matrix * * Conforms To: None. * * Declared In: SlidingMatrix.h * * *------------------------------------------------------------------------*/ #import "SlidingMatrix.h" static int rowDropped; static int rowDragged; static BOOL isDragging; static NXPoint currentMouse; #define BOUND(__a,__low,__high) MIN(MAX((__a),(__low)),(__high)) @implementation SlidingMatrix /*-------------------------------------------------------------------------- * Private Methods *------------------------------------------------------------------------*/ - _exchangeRowAt: (int) source with: (int) destination { int iterator; id sourceCell, destinationCell; for (iterator = 0; iterator < numCols; iterator++) { sourceCell = [self cellAt: source : iterator]; destinationCell = [self cellAt: destination : iterator]; [self putCell: sourceCell at: destination : iterator]; [self putCell: destinationCell at: source : iterator]; } return self; } - _reflectScroll { // If in a ScrollView, reflect scroll if drag is beyond visibleRect... id scrollView = [superview superview]; id clipView = superview; NXRect visibleRect, clipViewBoundsRect; NXCoord delta; [self getVisibleRect: &visibleRect]; delta = (currentMouse.y + cellSize.height) - (NX_HEIGHT (&visibleRect) + NX_Y (&visibleRect)); if (delta > 0.0) { [clipView getBounds: &clipViewBoundsRect]; NX_Y (&clipViewBoundsRect) += delta; [clipView rawScroll: &clipViewBoundsRect.origin]; [scrollView reflectScroll: clipView]; } else { delta = NX_Y (&visibleRect) - currentMouse.y; if (delta > 0.0) { [clipView getBounds: &clipViewBoundsRect]; NX_Y (&clipViewBoundsRect) -= delta; [clipView rawScroll: &clipViewBoundsRect.origin]; [scrollView reflectScroll: clipView]; } } return self; } - _reflectSlide { // Here's where we actually adjust the cells to reflect the slide. Insert // a new cell at the drop row (this moves any rows > than drop row by // one). Exchange the dragged cell with the newly inserted cell. Remove // the original dragged row. If user has dragged beyond last cell, add to // end. int rowDraggedOffset = 0; NXRect rect; NXPoint mouseLocation; [window getMouseLocation: &mouseLocation]; [self getBounds: &rect]; [self convertRect: &rect toView: nil]; if (rowDropped == numRows -1 && mouseLocation.y < NX_Y (&rect)) rowDropped++; [window disableFlushWindow]; [self insertRowAt: rowDropped]; if (rowDropped < rowDragged) { rowDragged++; rowDraggedOffset = 1; } selectedRow = rowDropped; [self _exchangeRowAt: rowDragged with: rowDropped]; [self removeRowAt: rowDragged andFree: YES]; rowDragged -= rowDraggedOffset; [self display]; [window reenableFlushWindow]; [window flushWindow]; return self; } - (BOOL) _notifyDelegateWillSlideFromRow: (int) sourceRow { if (delegate && [delegate respondsTo: @selector (slidingMatrix:willSlideFromRow:)]) return [delegate slidingMatrix: self willSlideFromRow: sourceRow ]; return YES; } - (BOOL) _notifyDelegateWillSlideToRow: (int) destinationRow { if (delegate && [delegate respondsTo: @selector (slidingMatrix:willSlideToRow:)]) return [delegate slidingMatrix: self willSlideToRow: destinationRow]; return YES; } - _notifyDelegateDidSlideFromRow: (int) sourceRow toRow: (int) destinationRow { if (delegate && [delegate respondsTo: @selector (slidingMatrix:didSlideFromRow:toRow:)]) [delegate slidingMatrix:self didSlideFromRow:sourceRow toRow:destinationRow]; return self; } /*-------------------------------------------------------------------------- * Initialization and Freeing *------------------------------------------------------------------------*/ - initFrame: (const NXRect*) frameRect { id buttonCellPrototype = [[ButtonCell allocFromZone: [self zone]] initTextCell:"empty"]; [buttonCellPrototype setIconPosition:NX_ICONLEFT]; [buttonCellPrototype setBordered:NO]; [buttonCellPrototype setIcon:"empty"]; [buttonCellPrototype setAlignment:NX_LEFTALIGNED]; [buttonCellPrototype setType:NX_ONOFF]; [super initFrame:(const NXRect *)frameRect mode:NX_RADIOMODE prototype:buttonCellPrototype numRows:0 numCols:0]; return self; } /*-------------------------------------------------------------------------- * Accessing the deleagate *------------------------------------------------------------------------*/ - delegate { return delegate; } - setDelegate: anObject { delegate = anObject; return self; } /*-------------------------------------------------------------------------- * Event Handling *------------------------------------------------------------------------*/ - mouseDown: (NXEvent*) theEvent { int column, originalEventMask; BOOL scrollViewFlag; NXRect cellFrame, visibleRect; NXCoord offset; NXEvent* nextEvent; // Is user control-dragging... if ( ! (theEvent->flags & NX_CONTROLMASK)) return [super mouseDown: theEvent]; // Is there a valid row under the mouse... currentMouse = theEvent->location; [self convertPoint: ¤tMouse fromView: nil]; [self getRow: &rowDragged andCol: &column forPoint: ¤tMouse]; if (rowDragged == -1) return [super mouseDown: theEvent]; if ([self _notifyDelegateWillSlideFromRow: rowDragged] == NO) return [super mouseDown: theEvent]; [self selectCellAt: rowDragged : column]; // Calculate offset (difference between mouse hit y coord and // cellFrame y coord). [self getCellFrame: &cellFrame at: rowDragged : column]; offset = currentMouse.y - NX_Y (&cellFrame); // Adjust currentMouse.y to cell frame boundary. currentMouse.y -= offset; // Prepare for event loop... [window makeFirstResponder: window]; originalEventMask = [window addToEventMask: NX_MOUSEDRAGGEDMASK]; scrollViewFlag = ([[superview superview] isKindOf: [ScrollView class]] ? YES : NO); isDragging = YES; while (isDragging) { nextEvent = [NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK]; switch (nextEvent->type) { case NX_MOUSEDRAGGED: isDragging = YES; currentMouse = nextEvent->location; [self convertPoint: ¤tMouse fromView: nil]; currentMouse.y -= offset; currentMouse.y = BOUND (currentMouse.y, NX_Y (&bounds), (NX_Y (&bounds) + NX_HEIGHT (&bounds) - cellSize.height)); if ([self getVisibleRect: &visibleRect] && scrollViewFlag) [self _reflectScroll]; [self displayFromOpaqueAncestor: &visibleRect :1 :YES]; break; case NX_MOUSEUP: isDragging = NO; currentMouse.y += cellSize.height / 2.0; if ( ! [self getRow:&rowDropped andCol:&column forPoint:¤tMouse]) { currentMouse.y += cellSize.height / 4.0; if ( ! [self getRow:&rowDropped andCol:&column forPoint:¤tMouse]) break; } if ([self _notifyDelegateWillSlideToRow: rowDropped]) { [self _reflectSlide]; [self selectCellAt: rowDropped : column]; [self _notifyDelegateDidSlideFromRow:rowDragged toRow:rowDropped]; } break; } } [self display]; [window setEventMask: originalEventMask]; return self; } /*-------------------------------------------------------------------------- * Drawing Methods *------------------------------------------------------------------------*/ - drawSelf: (const NXRect*)rects : (int) rectCount { int iterator; NXRect rect; if (! isDragging) return [super drawSelf: rects : rectCount]; [super drawSelf: rects : rectCount]; PSgsave (); PSsetgray ([window backgroundGray]); for (iterator = 0; iterator < numCols; iterator++) { [self getCellFrame: &rect at: rowDragged : iterator]; NXRectFill (&rect); } PSgrestore(); for (iterator = 0; iterator < numCols; iterator++) { [self getCellFrame: &rect at: rowDragged : iterator]; NX_Y (&rect) = currentMouse.y; [[self cellAt: rowDragged : iterator] drawSelf: &rect inView: self]; } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.