home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Palettes / MiscTableScroll / MiscBorderView.M < prev    next >
Encoding:
Text File  |  1996-02-11  |  38.3 KB  |  1,315 lines

  1. //=============================================================================
  2. //
  3. //        Copyright (C) 1995, 1996 by Paul S. McCarthy and Eric Sunshine.
  4. //                Written by Paul S. McCarthy and Eric Sunshine.
  5. //                            All Rights Reserved.
  6. //
  7. //        This notice may not be removed from this source code.
  8. //
  9. //        This object is included in the MiscKit by permission from the authors
  10. //        and its use is governed by the MiscKit license, found in the file
  11. //        "License.rtf" in the MiscKit distribution.    Please refer to that file
  12. //        for a list of all applicable permissions and restrictions.
  13. //        
  14. //=============================================================================
  15. //-----------------------------------------------------------------------------
  16. // MiscBorderView.M
  17. //
  18. //        View class for the row/column borders on a MiscTableView.
  19. //        Supports resizing, dragging.
  20. //
  21. //-----------------------------------------------------------------------------
  22. //-----------------------------------------------------------------------------
  23. // $Id: MiscBorderView.M,v 1.9 96/02/12 00:04:25 sunshine Exp $
  24. // $Log:        MiscBorderView.M,v $
  25. //    Revision 1.9  96/02/12    00:04:25  sunshine
  26. //    no comment.
  27. //    
  28. //    Revision 1.8  96/01/17    05:17:09  sunshine
  29. //    Fixed crasher.    Was allocating drag-cache window (an alloc once free never
  30. //    object) from [self zone].  When the zone was destroyed the window pointer
  31. //    (in a static variable) ceased to point to valid memory.
  32. //    
  33. //    Revision 1.7  96/01/16    19:51:25  zarnuk
  34. //    Eliminated a lot of unnecessary drawing while dragging.
  35. //-----------------------------------------------------------------------------
  36. #import "MiscBorderView.h"
  37. #import "MiscBorderCell.h"
  38. #import "MiscHighlightTracker.h"
  39. #import "MiscListTracker.h"
  40. #import "MiscRadioTracker.h"
  41. #import "MiscTableBorder.h"
  42. #import "MiscTableView.h"
  43. #import "MiscTableWell.h"
  44. #import <misckit/MiscTableScroll.h>
  45. #import <misckit/MiscTableTypes.h>
  46.  
  47. #import <new.h>
  48.  
  49. extern "Objective-C" {
  50. #import <appkit/Application.h>
  51. #import <appkit/ClipView.h>
  52. #import <appkit/Font.h>
  53. #import <appkit/NXCursor.h>
  54. #import <appkit/NXImage.h>
  55. #import <appkit/Text.h>
  56. #import <appkit/Window.h>
  57. #import <appkit/graphics.h>
  58. #import <appkit/timer.h>
  59. #import <objc/NXBundle.h>
  60. #import <dpsclient/dpsNeXT.h>
  61. #import <dpsclient/wraps.h>
  62. }
  63.  
  64. extern "C" {
  65. #import <assert.h>
  66. #import <float.h>
  67. #import <limits.h>
  68. #import <math.h>
  69. #import <string.h>        // memset().
  70. #import <stdio.h>        // FILENAME_MAX
  71. }
  72.  
  73. #define MISC_RESIZE_EPSILON        5
  74. #define MISC_FRAME_HEIGHT        18
  75. #define MISC_FRAME_WIDTH        46
  76.  
  77. static NXCursor* horzCursor = 0;
  78. static NXCursor* vertCursor = 0;
  79.  
  80. static inline double dmin( double a, double b ) { return (a < b ? a : b); }
  81. static inline double dmax( double a, double b ) { return (a > b ? a : b); }
  82.  
  83.  
  84. //----------------------------------------------------------------------------
  85. // startTimer
  86. //----------------------------------------------------------------------------
  87. static inline void startTimer( NXTrackingTimer*& timer )
  88.     {
  89.     if (timer == 0)
  90.         timer = NXBeginTimer( 0, 0.1, 0.1 );
  91.     }
  92.  
  93.  
  94. //----------------------------------------------------------------------------
  95. // stopTimer
  96. //----------------------------------------------------------------------------
  97. static inline void stopTimer( NXTrackingTimer*& timer )
  98.     {
  99.     if (timer)
  100.         {
  101.         NXEndTimer( timer );
  102.         timer = 0;
  103.         }
  104.     }
  105.  
  106.  
  107.  
  108. //=============================================================================
  109. // IMPLEMENTATION
  110. //=============================================================================
  111. @implementation MiscBorderView
  112.  
  113. //-----------------------------------------------------------------------------
  114. // + cursorFromImageName:
  115. //        NOTE: Cannot use [self zone] in a class (factory) method
  116. //        like this one, hence no allocFromZone:.
  117. //-----------------------------------------------------------------------------
  118. + (NXCursor*) cursorFromImageName:(char const*)name
  119.     {
  120.     NXImage* image = [NXImage findImageNamed:name];
  121.     if (image == 0)
  122.         {
  123.         char path[ FILENAME_MAX + 1 ];
  124.         [[NXBundle bundleForClass:self]
  125.                 getPath:path forResource:name ofType:"tiff"];
  126.         image = [[NXImage alloc] initFromFile:path];
  127.         [image setName:name];
  128.         }
  129.     NXPoint const hot = { 8, 8 };
  130.     NXCursor* cursor = [[NXCursor alloc] initFromImage: image];
  131.     [cursor setHotSpot:&hot];
  132.     return cursor;
  133.     }
  134.  
  135.  
  136. //-----------------------------------------------------------------------------
  137. // + initialize
  138. //-----------------------------------------------------------------------------
  139. + initialize
  140.     {
  141.     if (horzCursor == 0)
  142.         {
  143.         horzCursor = [self cursorFromImageName:"MiscHorzResizeCursor"];
  144.         vertCursor = [self cursorFromImageName:"MiscVertResizeCursor"];
  145.         }
  146.     return self;
  147.     }
  148.  
  149.  
  150. //-----------------------------------------------------------------------------
  151. // TYPE VARIATIONS
  152. //-----------------------------------------------------------------------------
  153.  
  154. - (NXCoord) frameHeight
  155.         { return (isHorz ? MISC_FRAME_HEIGHT : MISC_FRAME_WIDTH); }
  156. - (NXCursor*) cursor
  157.         { return isHorz ? horzCursor : vertCursor; }
  158. - (MiscBorderType) borderType
  159.         { return isHorz ? MISC_COL_BORDER : MISC_ROW_BORDER; }
  160. - (MiscBorderType) otherBorderType
  161.         { return isHorz ? MISC_ROW_BORDER : MISC_COL_BORDER; }
  162. - (MiscTableBorder*) otherBorder
  163.         { return [scroll border: [self otherBorderType]]; }
  164. - (void) clearOtherBorder { [self otherBorder]->selectionSet().empty(); }
  165. - cellAt: (MiscCoord_P) row : (MiscCoord_P) col
  166.     { return isHorz ? [scroll cellAt:row:col] : [scroll cellAt:col:row]; }
  167.  
  168. - (NXCoord) sizeWidth: (NXSize const*) size
  169.         { return isHorz ? size->width : size->height; }
  170. - (NXCoord) sizeHeight: (NXSize const*) size
  171.         { return isHorz ? size->height : size->width; }
  172.  
  173. - (NXCoord) pointX: (NXPoint const*) point
  174.         { return isHorz ? point->x : point->y; }
  175. - (NXCoord) pointY: (NXPoint const*) point
  176.         { return isHorz ? point->y : point->x; }
  177. - (void) point: (NXPoint*) point setX: (NXCoord) x
  178.         { if (isHorz) point->x = x; else point->y = x; };
  179. - (void) point: (NXPoint*) point setY: (NXCoord) y
  180.         { if (isHorz) point->y = y; else point->x = y; };
  181.  
  182. - (NXCoord)rectMinX:(NXRect const*)frameRect
  183.         { return isHorz ? NX_X(frameRect) : NX_Y(frameRect); }
  184. - (NXCoord)rectMaxX:(NXRect const*)frameRect
  185.         { return isHorz ? NX_MAXX(frameRect) : NX_MAXY(frameRect); }
  186. - (NXCoord)rectMinY:(NXRect const*)frameRect
  187.         { return isHorz ? NX_Y(frameRect) : NX_X(frameRect); }
  188. - (NXCoord)rectMaxY:(NXRect const*)frameRect
  189.         { return isHorz ? NX_MAXY(frameRect) : NX_MAXX(frameRect); }
  190. - (NXCoord)rectWidth:(NXRect const*)frameRect
  191.         { return isHorz ? NX_WIDTH(frameRect) : NX_HEIGHT(frameRect); }
  192. - (NXCoord)rectHeight:(NXRect const*)frameRect
  193.         { return isHorz ? NX_HEIGHT(frameRect) : NX_WIDTH(frameRect); }
  194.  
  195. - (void) setRect:(NXRect*)rect minX:(NXCoord)x
  196.         { if (isHorz) NX_X(rect) = x; else NX_Y(rect) = x; }
  197. - (void) setRect:(NXRect*)rect minY:(NXCoord)y
  198.         { if (isHorz) NX_Y(rect) = y; else NX_X(rect) = y; }
  199. - (void) setRect:(NXRect*)rect width:(NXCoord)width
  200.         { if (isHorz) NX_WIDTH(rect) = width; else NX_HEIGHT(rect) = width; }
  201. - (void) setRect:(NXRect*)rect height:(NXCoord)height
  202.         { if (isHorz) NX_HEIGHT(rect) = height; else NX_WIDTH(rect) = height; }
  203.  
  204. - (void) changeFrameIfNeeded
  205.     {
  206.     MiscPixels const my_width = (MiscPixels) floor([self rectWidth:&frame]);
  207.     MiscPixels const i_width = info->totalSize();
  208.     if (my_width != i_width)
  209.         {
  210.         NXRect rect = frame;
  211.         [window invalidateCursorRectsForView:self];
  212.         [self setRect:&rect width:i_width];
  213.         [self sizeTo: rect.size.width : rect.size.height ];
  214.         [[scroll docView] adjustSize];
  215.         }
  216.     }
  217.  
  218. - (void) setPos:(MiscCoord_V)pos width:(MiscPixels)size
  219.     {
  220.     MiscCoord_P pPos = info->visualToPhysical(pos);
  221.     if (isHorz)
  222.         [scroll setCol:pPos size:(NXCoord)size];
  223.     else
  224.         [scroll setRow:pPos size:(NXCoord)size];
  225.     [self changeFrameIfNeeded];
  226.     [window invalidateCursorRectsForView:self];
  227.     [scroll update];
  228.     }
  229.  
  230. - (void) moveFrom:(MiscCoord_V)from to:(MiscCoord_V)to
  231.     {
  232.     if (isHorz)
  233.         [scroll moveColFrom:from to:to];
  234.     else
  235.         [scroll moveRowFrom:from to:to];
  236.     [window invalidateCursorRectsForView:self];
  237.     [scroll update];
  238.     }
  239.  
  240.  
  241.  
  242. //-----------------------------------------------------------------------------
  243. // - initFrame:scroll:info:type:
  244. //-----------------------------------------------------------------------------
  245. - initFrame: (NXRect const*) frameRect
  246.      scroll: (MiscTableScroll*) i_scroll
  247.        info: (MiscTableBorder*) i_info
  248.        type: (MiscBorderViewType) type
  249.     {
  250.     NXZone* const z = [self zone];
  251.  
  252.     [super initFrame: 0];
  253.     [self setFlipped:YES];
  254.     [self setOpaque:YES];
  255.     [self setClipping:NO];
  256.  
  257.     isHorz = (type == MISC_COL_BORDER_VIEW);
  258.     scroll = i_scroll;
  259.     info = i_info;
  260.     theCell = [[MiscBorderCell allocFromZone:z] initTextCell:"Kilroy"];
  261.  
  262.     oldSel = new( NXZoneMalloc(z,sizeof(*oldSel)) ) MiscSparseSet;
  263.     [self setSelectionMode: [scroll selectionMode]];
  264.  
  265.     NXRect myFrame = {{0,0},{0,0}};
  266.     if (frameRect != 0)
  267.         myFrame.origin = frameRect->origin;
  268.     [self setRect: &myFrame width: i_info->totalSize()];
  269.     [self setRect: &myFrame height: [self frameHeight]];
  270.     [self setFrame: &myFrame];
  271.     return self;
  272.     }
  273.  
  274.  
  275. //-----------------------------------------------------------------------------
  276. // - free
  277. //-----------------------------------------------------------------------------
  278. - free
  279.     {
  280.     [theCell free];
  281.     [tracker free];
  282.     if (oldSel != 0)
  283.         {
  284.         oldSel->MiscSparseSet::~MiscSparseSet();
  285.         NXZoneFree( [self zone], oldSel );
  286.         }
  287.     return [super free];
  288.     }
  289.  
  290.  
  291.  
  292. //=============================================================================
  293. // CONVERSIONS
  294. //=============================================================================
  295. //-----------------------------------------------------------------------------
  296. // - range::fromRect:
  297. //
  298. //        Returns by reference the range of visual slots contained in rect.
  299. //        rMin is inclusive, rMax is exclusive.
  300. //-----------------------------------------------------------------------------
  301. - (void) range: (MiscCoord_V*)rMin : (MiscCoord_V*)rMax
  302.     fromRect: (NXRect const*)rect
  303.     {
  304.     *rMin = info->visualForOffset(MiscPixels(floor([self rectMinX:rect])));
  305.     *rMax = info->visualForOffset(MiscPixels(floor([self rectMaxX:rect]))) + 1;
  306.     }
  307.  
  308.  
  309. //-----------------------------------------------------------------------------
  310. // - rect:forPos:
  311. //-----------------------------------------------------------------------------
  312. - (void) rect:(NXRect*)nxrect forPos:(MiscCoord_V)pos
  313.     {
  314.     [self getBounds:nxrect];
  315.     [self setRect: nxrect minX: info->getOffset(pos)];
  316.     [self setRect: nxrect width: info->effectiveSize(pos)];
  317.     }
  318.  
  319.  
  320.  
  321. //=============================================================================
  322. // DRAWING
  323. //=============================================================================
  324. //-----------------------------------------------------------------------------
  325. // - getVisibleRange::
  326. //
  327. //        Returns by reference the range of visual slots contained in the visible
  328. //        rectangle.    rMin is inclusive, rMax is exclusive.
  329. //-----------------------------------------------------------------------------
  330. - (void) getVisibleRange: (MiscCoord_V*)rMin : (MiscCoord_V*)rMax
  331.     {
  332.     NXRect visRect;
  333.     [superview getDocVisibleRect:&visRect];
  334.     [self range:rMin:rMax fromRect:&visRect];
  335.     }
  336.  
  337.  
  338. //-----------------------------------------------------------------------------
  339. // drewPos:
  340. //
  341. //        Keeps the old selection sets up to date whenever we draw a cell.  This
  342. //        way -reflectSelection has valid data to work from.
  343. //-----------------------------------------------------------------------------
  344. - (void) drewPos: (MiscCoord_V)slot
  345.     {
  346.     BOOL isSelected = info->selectionSet().contains( slot );
  347.     if (isSelected != oldSel->contains(slot))
  348.         {
  349.         if (isSelected)
  350.             oldSel->add( slot );
  351.         else
  352.             oldSel->remove( slot );
  353.         }
  354.     }
  355.  
  356.  
  357. //-----------------------------------------------------------------------------
  358. // - drawPos:inRect:controlView:
  359. //-----------------------------------------------------------------------------
  360. - (void) drawPos: (MiscCoord_V) pos inRect:(NXRect const*) rect
  361.     controlView: (View*) controlView
  362.     {
  363.     [theCell setStringValue: info->getTitle(pos)];
  364.     [theCell setState: info->selectionSet().contains(pos)];
  365.     [theCell drawSelf: rect inView: controlView];
  366.     }
  367.  
  368.  
  369. //-----------------------------------------------------------------------------
  370. // - drawPos:updateSel:
  371. //-----------------------------------------------------------------------------
  372. - (void) drawPos: (MiscCoord_V) pos updateSel: (BOOL) updateSel
  373.     {
  374.     if (0 <= pos && pos < info->count())
  375.         {
  376.         NXRect rect;
  377.         [self rect:&rect forPos:pos];
  378.         [self drawPos:pos inRect:&rect controlView: self];
  379.         if (updateSel)
  380.             [self drewPos:pos];
  381.         }
  382.     }
  383.  
  384.  
  385. //-----------------------------------------------------------------------------
  386. // - drawPos:
  387. //-----------------------------------------------------------------------------
  388. - (void) drawPos: (MiscCoord_V) pos
  389.     {
  390.     [self drawPos:pos updateSel:YES];
  391.     }
  392.  
  393.  
  394. //-----------------------------------------------------------------------------
  395. // - drawRect:
  396. //-----------------------------------------------------------------------------
  397. - (void) drawRect: (NXRect const*) rect
  398.     {
  399.     MiscCoord_V pos_min;
  400.     MiscCoord_V pos_max;
  401.     [self range:&pos_min:&pos_max fromRect:rect];
  402.     for (MiscCoord_V pos = pos_min;     pos < pos_max;     pos++)
  403.         [self drawPos:pos];
  404.     }
  405.  
  406.  
  407. //-----------------------------------------------------------------------------
  408. // - drawSelf::
  409. //-----------------------------------------------------------------------------
  410. - drawSelf: (NXRect const*) rects :(int) nrects
  411.     {
  412.     if (nrects == 1)
  413.         [self drawRect: rects];
  414.     else if (nrects == 3)
  415.         {
  416.         [self drawRect: ++rects];
  417.         [self drawRect: ++rects];
  418.         }
  419.     return self;
  420.     }
  421.  
  422.  
  423.  
  424. //-----------------------------------------------------------------------------
  425. // - drawSlot:    [public]
  426. //-----------------------------------------------------------------------------
  427. - (void) drawSlot: (MiscCoord_V) n
  428.     {
  429.     MiscCoord_V rMin, rMax;
  430.     [self getVisibleRange:&rMin:&rMax];
  431.     if (rMin <= n && n < rMax)
  432.         {
  433.         if ([self isAutodisplay] && [self canDraw])
  434.             {
  435.             [self lockFocus];
  436.             [self drawPos:n];
  437.             [self unlockFocus];
  438.             }
  439.         else
  440.             {
  441.             [self setNeedsDisplay:YES];
  442.             }
  443.         }
  444.     }
  445.  
  446.  
  447.  
  448. //=============================================================================
  449. // SELECTION
  450. //=============================================================================
  451. //-----------------------------------------------------------------------------
  452. // - setSelectionMode:
  453. //-----------------------------------------------------------------------------
  454. - (void) setSelectionMode: (MiscSelectionMode) mode
  455.     {
  456.     NXZone* const z = [self zone];
  457.     if (tracker)
  458.         [tracker free];
  459.     switch (mode)
  460.         {
  461.         case MISC_LIST_MODE:
  462.             tracker = [MiscListTracker allocFromZone:z];
  463.             break;
  464.         case MISC_RADIO_MODE:
  465.             tracker = [MiscRadioTracker allocFromZone:z];
  466.             break;
  467.         case MISC_HIGHLIGHT_MODE:
  468.             tracker = [MiscHighlightTracker allocFromZone:z];
  469.             break;
  470.         }
  471.     [tracker initBorder: info];
  472.     }
  473.  
  474.  
  475. //-----------------------------------------------------------------------------
  476. // - reflectSelection
  477. //-----------------------------------------------------------------------------
  478. - (void) reflectSelection
  479.     {
  480.     if ([self canDraw])
  481.         {
  482.         MiscSparseSet const& newSel = info->selectionSet();
  483.  
  484.         MiscCoord_V rMin, rMax;
  485.         [self getVisibleRange:&rMin:&rMax];
  486.     
  487.         [window disableFlushWindow];
  488.         int locked = 0;
  489.         for (MiscCoord_V i = rMin;    i < rMax;  i++)
  490.             {
  491.             if (oldSel->contains(i) != newSel.contains(i))
  492.                 {
  493.                 if (!locked)
  494.                     {
  495.                     locked = 1;
  496.                     [self lockFocus];
  497.                     }
  498.                 [self drawPos:i updateSel:NO];
  499.                 }
  500.             }
  501.         if (locked)
  502.             [self unlockFocus];
  503.     
  504.         [[window reenableFlushWindow] flushWindow];
  505.         *oldSel = newSel;
  506.         }
  507.     }
  508.  
  509.  
  510. //-----------------------------------------------------------------------------
  511. // - selectPos:
  512. //-----------------------------------------------------------------------------
  513. - (void) selectPos: (MiscCoord_V) pos
  514.     {
  515.     MiscSparseSet& s = info->selectionSet();
  516.     s.empty();
  517.     s.add( pos );
  518.     [scroll selectionChanged];
  519.     }
  520.  
  521.  
  522.  
  523. //=============================================================================
  524. // CURSOR MANAGEMENT
  525. //=============================================================================
  526. //-----------------------------------------------------------------------------
  527. // - cursorRect:forPos:
  528. //-----------------------------------------------------------------------------
  529. - (BOOL) cursorRect:(NXRect*)nxrect forPos:(MiscCoord_V)pos;
  530.     {
  531.     MiscPixels const pos_width = info->effectiveSize(pos);
  532.     if (pos_width > 0)
  533.         {
  534.         MiscPixels const pos_offset = info->getOffset(pos);
  535.         MiscPixels const min_x = pos_offset + pos_width - MISC_RESIZE_EPSILON;
  536.         *nxrect = bounds;
  537.         [self setRect:nxrect minX:min_x];
  538.         [self setRect:nxrect width:MISC_RESIZE_EPSILON];
  539.         return YES;
  540.         }
  541.     return NO;
  542.     }
  543.  
  544.  
  545. //-----------------------------------------------------------------------------
  546. // - resetCursorRects
  547. //-----------------------------------------------------------------------------
  548. - resetCursorRects
  549.     {
  550.     if (info->isSizeable())
  551.         {
  552.         NXCursor* const cursor = [self cursor];
  553.         MiscCoord_V min_pos, max_pos;
  554.         [self getVisibleRange:&min_pos:&max_pos];
  555.         int const count = info->count();
  556.         if (0 <= min_pos && min_pos < count)
  557.             {
  558.             NXRect rect;
  559.             int const lim = (max_pos <= count) ? max_pos : count;
  560.             for (MiscCoord_V pos = min_pos;     pos < lim;     pos++)
  561.                 if (info->isSizeable(pos) && [self cursorRect:&rect forPos:pos])
  562.                     [self addCursorRect:&rect cursor:cursor];
  563.             }
  564.         }
  565.     return self;
  566.     }
  567.  
  568.  
  569. //-----------------------------------------------------------------------------
  570. // - refresh
  571. //-----------------------------------------------------------------------------
  572. - (void) refresh
  573.     {
  574.     [self changeFrameIfNeeded];
  575.     if ([self canDraw])
  576.         {
  577.         [window disableFlushWindow];
  578.         NXRect rect;
  579.         [superview getDocVisibleRect:&rect];
  580.         [self lockFocus];
  581.         [self drawSelf:&rect:1];
  582.         [self unlockFocus];
  583.         [[window reenableFlushWindow] flushWindow];
  584.         }
  585.     }
  586.  
  587.  
  588.  
  589. //=============================================================================
  590. // MOUSE-TRACKING
  591. //=============================================================================
  592. //-----------------------------------------------------------------------------
  593. // - startTracking
  594. //-----------------------------------------------------------------------------
  595. - (void) startTracking
  596.     {
  597.     [self clearOtherBorder];
  598.     if ([window firstResponder] == [scroll docView])
  599.         [window makeFirstResponder: window];
  600.     }
  601.  
  602.  
  603. //-----------------------------------------------------------------------------
  604. // - endTracking:
  605. //-----------------------------------------------------------------------------
  606. - (void) endTracking: (MiscCoord_V)pos
  607.     {
  608.     if (pos < 0)
  609.         pos = 0;
  610.     else if (pos >= info->count())
  611.         pos = info->count() - 1;
  612.     [scroll border:[self borderType] setCursor:info->visualToPhysical(pos)];
  613.     [scroll selectText: self];
  614.     }
  615.  
  616.  
  617. //-----------------------------------------------------------------------------
  618. // - posForMousePt:
  619. //-----------------------------------------------------------------------------
  620. - (MiscCoord_V) posForMousePt: (NXPoint const*) p
  621.     {
  622.     MiscPixels pix = MiscPixels( floor([self pointX: p]) );
  623.     return (pix < [self rectMaxX: &bounds] ?
  624.                 info->visualForOffset( pix ) : info->count());
  625.     }
  626.  
  627.  
  628.  
  629. //=============================================================================
  630. // RESIZING
  631. //=============================================================================
  632. //-----------------------------------------------------------------------------
  633. // - resizeEvent:x:deltaX:minX:maxX:
  634. //-----------------------------------------------------------------------------
  635. - (int) resizeEvent:(NXEvent const*)p
  636.         x:(MiscPixels)x
  637.         deltaX:(MiscPixels)deltaX
  638.         minX:(MiscPixels)minX
  639.         maxX:(MiscPixels)maxX
  640.     {
  641.     NXRect docFrame;    [scroll getDocClipFrame: &docFrame];
  642.     NXRect clipFrame;    [superview getFrame: &clipFrame];
  643.     NXCoord const minDrawX = [self rectMinX: &clipFrame]; // scroll coords
  644.     NXCoord const maxDrawX = [self rectMaxX: &clipFrame]; // scroll coords
  645.  
  646.     x += deltaX;
  647.  
  648.     NXCoord draw_x;                // scroll coords
  649.     NXRect line;
  650.     [self setRect:&line height:[self rectHeight:&clipFrame] +
  651.                                 [self rectHeight:&docFrame] - 1 ];
  652.     [self setRect:&line width: 2 ];
  653.     [self setRect:&line minX: x - 1 ];
  654.     [self setRect:&line minY: 0 ];
  655.     [scroll convertPoint:&(line.origin) fromView:self];
  656.     draw_x = [self rectMinX:&line];
  657.  
  658.     BOOL did_scroll = NO;
  659.     BOOL in_bounds = (minDrawX <= draw_x && draw_x <= maxDrawX);
  660.  
  661.     [scroll lockFocus];
  662.     PSsetinstance(YES);
  663.     PSsetgray(NX_BLACK);
  664.  
  665.     if (in_bounds)
  666.         PSrectfill( line.origin.x, line.origin.y,
  667.                         line.size.width, line.size.height );
  668.  
  669.     NXTrackingTimer* timer = 0;
  670.     startTimer( timer );
  671.     NXEvent lastEvent = *p;
  672.  
  673.     while (1)
  674.         {
  675.         p = [NXApp getNextEvent:NX_MOUSEUPMASK |
  676.                                 NX_MOUSEDRAGGEDMASK |
  677.                                 NX_TIMERMASK ];
  678.         if (p == 0 || p->type == NX_MOUSEUP)
  679.             break;
  680.         if (p->type == NX_TIMER)
  681.             {
  682.             NXPoint mousePt = lastEvent.location;
  683.             [scroll convertPoint:&mousePt fromView:0];
  684.             if (mousePt.x < minDrawX || maxDrawX < mousePt.x)
  685.                 {
  686.                 PSsetinstance(NO);
  687.                 [self autoscroll: &lastEvent];
  688.                 PSsetinstance(YES);
  689.                 did_scroll = YES;
  690.                 }
  691.             }
  692.         else
  693.             lastEvent = *p;
  694.  
  695.         NXPoint new_loc = lastEvent.location;
  696.         [self convertPoint:&new_loc fromView:0];
  697.         MiscPixels mouseX = (MiscPixels) floor([self pointX:&new_loc]);
  698.         MiscPixels new_x = (mouseX + deltaX);
  699.         if (new_x < minX)
  700.             new_x = minX;
  701.         else if (new_x >= maxX)
  702.             new_x = maxX - 1;
  703.  
  704.         BOOL const did_move = (new_x != x);
  705.         if (did_move || did_scroll)
  706.             {
  707.             if (in_bounds && !did_scroll)
  708.                 PShideinstance( line.origin.x, line.origin.y,
  709.                                 line.size.width, line.size.height );
  710.             if (did_move)
  711.                 {
  712.                 x = new_x;
  713.                 [self setRect:&line minX: x - 1 ];
  714.                 [self setRect:&line minY:0];
  715.                 [scroll convertPoint:&(line.origin) fromView:self];
  716.                 draw_x = [self rectMinX:&line];
  717.                 in_bounds = (minDrawX <= draw_x && draw_x <= maxDrawX);
  718.                 }
  719.  
  720.             if (in_bounds)
  721.                 PSrectfill( line.origin.x, line.origin.y,
  722.                                 line.size.width, line.size.height );
  723.             did_scroll = NO;
  724.             }
  725.         }
  726.  
  727.     stopTimer( timer );
  728.  
  729.     if (in_bounds)
  730.         PShideinstance( line.origin.x, line.origin.y,
  731.                         line.size.width, line.size.height );
  732.  
  733.     PSsetinstance(NO);
  734.     [scroll unlockFocus];
  735.  
  736.     x -= deltaX;
  737.     return x;
  738.     }
  739.  
  740.  
  741. //-----------------------------------------------------------------------------
  742. // - resizeEvent:inPos:atX:deltaX:finalWidth:
  743. //-----------------------------------------------------------------------------
  744. - (BOOL) resizeEvent: (NXEvent const*) p
  745.          inPos: (MiscCoord_V) pos
  746.          atX: (MiscPixels) x_origin
  747.          deltaX: (MiscPixels) delta_x
  748.          finalWidth: (MiscPixels*) finalWidth
  749.     {
  750.     MiscPixels const org_x = info->getOffset(pos);
  751.     MiscPixels const min_x = org_x + info->effectiveMinSize(pos);
  752.     MiscPixels const max_x = org_x + info->effectiveMaxSize(pos) + 1;
  753.     MiscPixels const curr_x = [self resizeEvent:p x:x_origin deltaX:delta_x
  754.                                 minX:min_x maxX:max_x];
  755.     MiscPixels final_delta = curr_x - x_origin;
  756.     if (final_delta != 0)
  757.         {
  758.         *finalWidth = info->effectiveSize(pos) + final_delta;
  759.         return YES;
  760.         }
  761.  
  762.     return NO;
  763.     }
  764.  
  765.  
  766. //-----------------------------------------------------------------------------
  767. // - inHotZone:forPos:atX:deltaX:
  768. //-----------------------------------------------------------------------------
  769. - (BOOL) inHotZone: (NXPoint const*) pt
  770.         forPos: (MiscCoord_V*) pos
  771.         atX: (MiscPixels*) pos_x
  772.         deltaX: (MiscPixels*) delta_x
  773.     {
  774.     if (info->isSizeable())
  775.         {
  776.         MiscCoord_V const plim = info->count();
  777.         MiscPixels x = (MiscPixels) floor([self pointX:pt]);
  778.         MiscCoord_V p = info->visualForOffset(x);
  779.         if (0 <= p && p < plim)
  780.             {
  781.             MiscPixels max_x = info->getOffset(p) + info->effectiveSize(p);
  782.             MiscPixels delta = max_x - x;
  783.         
  784.             if (0 <= delta && delta <= MISC_RESIZE_EPSILON)
  785.                 {
  786.                 do { p++; } while (p < plim && info->effectiveSize(p) <= 0);
  787.                 p--;
  788.                 if (0 <= p && p < plim && info->isSizeable(p))
  789.                     {
  790.                     *pos = p;
  791.                     *pos_x = x;
  792.                     *delta_x = delta;
  793.                     return YES;
  794.                     }
  795.                 }
  796.             }
  797.         }
  798.  
  799.     return NO;
  800.     }
  801.  
  802.  
  803. //-----------------------------------------------------------------------------
  804. // - adjustSize
  805. //-----------------------------------------------------------------------------
  806. - (void) adjustSize
  807.     {
  808.     [self changeFrameIfNeeded];
  809.     }
  810.  
  811.  
  812.  
  813. //=============================================================================
  814. // DRAGGING
  815. //=============================================================================
  816. //-----------------------------------------------------------------------------
  817. // - drawDocCells:at:controlView
  818. //-----------------------------------------------------------------------------
  819. - (void) drawDocCells: (MiscCoord_V) pos at: (NXPoint const*) pt
  820.     controlView: (View*) controlView
  821.     {
  822.     NXRect rDoc;
  823.     [[scroll docView] getVisibleRect: &rDoc];
  824.     MiscTableBorder* b = [self otherBorder];
  825.     MiscCoord_V sMin = b->visualForOffset(MiscPixels([self rectMinY: &rDoc]));
  826.     MiscCoord_V sMax = b->visualForOffset(MiscPixels([self rectMaxY: &rDoc]));
  827.     if (sMin >= 0 && sMax >= 0)
  828.         {
  829.         MiscCoord_P p_pos = info->visualToPhysical( pos );
  830.         NXCoord delta = [self rectMinY: &rDoc] - b->getOffset( sMin );
  831.     
  832.         NXRect r = {{0,0},{0,0}};
  833.         [self setRect: &r minY: [self pointY: pt] - delta];
  834.         [self setRect: &r width: info->effectiveSize( pos )];
  835.     
  836.         for (int i = sMin; i <= sMax; i++)
  837.             {
  838.             id cell = [self cellAt:b->visualToPhysical(i):p_pos];
  839.             [self setRect: &r height: b->effectiveSize(i)];
  840.             [cell drawSelf: &r inView: controlView];
  841.             [self setRect:&r minY:[self rectMinY:&r] + [self rectHeight:&r]];
  842.             }
  843.         }
  844.     }
  845.  
  846.  
  847. //-----------------------------------------------------------------------------
  848. // - setDragCache:forPos:
  849. //
  850. //        NOTE *1*: We create a special window just for the sake of getting the
  851. //                text on the drag-cache to display properly. 1) By creating a
  852. //                window, the cells have an object to which they can send their
  853. //                getFieldEditor:for: message.  2) By providing a view which is
  854. //                at least as large as the drag-cache we avoid clipping problems.
  855. //                If it wasn't large enough the text would get clipped at the
  856. //                wrong places.
  857. //        NOTE *2*: The weird combination of non-deferred window plus
  858. //                -reenableDisplay was necessary to get the text to actually
  859. //                display.  Without both of them text wouldn't draw at all.
  860. //                Let's have a look at that AppKit source!
  861. //-----------------------------------------------------------------------------
  862. - (void) setDragCache: (NXImage*) cache forPos: (MiscCoord_V) pos
  863.     {
  864.     Window* w = [[Window allocFromZone: [self zone]]            // NOTE *1*
  865.                 initContent: 0 style: NX_PLAINSTYLE
  866.                 backing: NX_NONRETAINED buttonMask: 0 defer: NO];
  867.     [w reenableDisplay];                                        // NOTE *2*
  868.     [[w contentView] setFlipped: YES];
  869.  
  870.     NXRect rDoc;        [[scroll docView] getVisibleRect: &rDoc];
  871.     NXRect rClip;        [superview getFrame: &rClip];
  872.     [scroll convertRect: &rDoc fromView: [scroll docView]];
  873.  
  874.     NXRect r = {{0,0},{0,0}};
  875.     [self setRect: &r width: info->effectiveSize( pos )];
  876.     [self setRect: &r height:
  877.                 ([self rectHeight: &rClip] + [self rectHeight: &rDoc])];
  878.  
  879.     NXRect rBorder = r;
  880.     [self setRect: &rBorder height: [self rectHeight: &rClip]];
  881.  
  882.     NXRect rContent = r;
  883.     [self setRect: &rContent minY: [self rectHeight: &rClip]];
  884.  
  885.     [w sizeWindow: NX_WIDTH(&r) : NX_HEIGHT(&r)];
  886.     [cache setFlipped: YES];
  887.     [cache setSize: &r.size];
  888.     [cache lockFocus];
  889.     [self drawDocCells: pos at: &rContent.origin controlView: [w contentView]];
  890.     [self drawPos: pos inRect: &rBorder controlView: [w contentView]];
  891.     [cache unlockFocus];
  892.  
  893.     [w free];
  894.     }
  895.  
  896.  
  897. //-----------------------------------------------------------------------------
  898. // - setVisibleCache:min:max:
  899. //-----------------------------------------------------------------------------
  900. - (void) setVisibleCache:(NXImage*)cache min:(NXCoord*)pMin max:(NXCoord*)pMax
  901.     {
  902.     NXRect rDoc;        [[scroll docView] getVisibleRect: &rDoc];
  903.     NXRect rVis;        [self getVisibleRect: &rVis];
  904.     *pMin = [self rectMinX: &rVis];
  905.     *pMax = [self rectMaxX: &rVis];
  906.     [scroll convertRect: &rDoc fromView: [scroll docView]];
  907.     [scroll convertRect: &rVis fromView: self];
  908.  
  909.     NXRect r;
  910.     [self setRect: &r minX: [self rectMinX: &rVis]];
  911.     [self setRect: &r minY: [self rectMinY: &rVis]];
  912.     [self setRect: &r width: [self rectWidth: &rVis]];
  913.     [self setRect: &r height:
  914.                 ([self rectHeight: &rVis] + [self rectHeight: &rDoc])];
  915.  
  916.     [scroll convertRect: &r toView: 0];
  917.     [cache setSize: &r.size];
  918.     [cache lockFocus];
  919.     PScomposite( NX_X(&r), NX_Y(&r), NX_WIDTH(&r), NX_HEIGHT(&r),
  920.                 [window gState], 0.0, 0.0, NX_COPY );
  921.     [cache unlockFocus];
  922.     }
  923.  
  924.  
  925. //-----------------------------------------------------------------------------
  926. // - setWells::forPos:
  927. //-----------------------------------------------------------------------------
  928. - (void) setWells: (MiscTableWell**) w1 : (MiscTableWell**) w2
  929.     forPos: (MiscCoord_V) pos
  930.     {
  931.     NXZone* const z = [self zone];
  932.     MiscTableView* doc = [scroll docView];
  933.     NXRect rDoc;        [doc getVisibleRect: &rDoc];
  934.     NXRect rClip;        [superview getFrame: &rClip];
  935.  
  936.     NXRect r = {{0,0},{0,0}};
  937.     [self setRect: &r minX: info->getOffset( pos )];
  938.     [self setRect: &r width: info->effectiveSize( pos )];
  939.     [self setRect: &r height: [self rectHeight: &rClip]];
  940.  
  941.     *w1 = [[MiscTableWell allocFromZone:z] initFrame: &r];
  942.     [self addSubview: *w1];
  943.  
  944.     [self setRect: &r minY: [self rectMinY: &rDoc]];
  945.     [self setRect: &r height: [self rectHeight: &rDoc]];
  946.     *w2 = [[MiscTableWell allocFromZone:z] initFrame: &r];
  947.     [doc addSubview: *w2];
  948.  
  949.     [*w1 display];
  950.     [*w2 display];
  951.     }
  952.  
  953.  
  954. //-----------------------------------------------------------------------------
  955. // - clearWells::
  956. //-----------------------------------------------------------------------------
  957. - (void) clearWells: (MiscTableWell**) w1 : (MiscTableWell**) w2
  958.     {
  959.     [*w1 removeFromSuperview];
  960.     [*w2 removeFromSuperview];
  961.     [*w1 free];
  962.     [*w2 free];
  963.     *w1 = 0;
  964.     *w2 = 0;
  965.     // NOTE: Does not need display here.  Everything will get displayed later.
  966.     }
  967.  
  968.  
  969. //-----------------------------------------------------------------------------
  970. // - offsetFromEvent:
  971. //-----------------------------------------------------------------------------
  972. - (NXCoord) offsetFromEvent: (NXEvent const*) ev
  973.     {
  974.     NXPoint mLoc = ev->location;
  975.     [self convertPoint: &mLoc fromView: 0];
  976.     return floor( [self pointX: &mLoc] );
  977.     }
  978.  
  979.  
  980. //-----------------------------------------------------------------------------
  981. // - calcDrop::
  982. //-----------------------------------------------------------------------------
  983. - (MiscCoord_V) calcDrop: (MiscCoord_V) fromPos
  984.                         : (NXPoint const*) mouseDownPt
  985.                         : (NXPoint const*) mouseUpPt
  986.     {
  987.     MiscCoord_V toPos = fromPos;
  988.  
  989.     MiscPixels const start_pos = (MiscPixels) floor([self pointX:mouseDownPt]);
  990.     MiscPixels const end_pos   = (MiscPixels) floor([self pointX:mouseUpPt]);
  991.     MiscPixels const delta_pos = (end_pos - start_pos);
  992.  
  993.     MiscPixels const SLOP = 4;
  994.     if (delta_pos < -SLOP || SLOP < delta_pos)
  995.         {
  996.         MiscPixels const start_ofs = info->getOffset( fromPos );
  997.         MiscPixels drop_pos = start_ofs + delta_pos;
  998.         if (delta_pos < 0)
  999.             drop_pos += SLOP;
  1000.         else
  1001.             drop_pos += info->effectiveSize(fromPos) - SLOP;
  1002.         toPos = info->visualForOffset( drop_pos );
  1003.         if (toPos < 0)
  1004.             toPos = 0;
  1005.         }
  1006.  
  1007.     return toPos;
  1008.     }
  1009.  
  1010.  
  1011. //-----------------------------------------------------------------------------
  1012. // - dragEvent:inPos:
  1013. //-----------------------------------------------------------------------------
  1014. - (MiscCoord_V) dragEvent: (NXEvent*) event inPos: (MiscCoord_V) pos
  1015.     {
  1016.     int const WANTED = (NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK | NX_TIMERMASK);
  1017.     NXPoint mouseDownPt = event->location;
  1018.  
  1019.     [self convertPoint:&mouseDownPt fromView:0];
  1020.     NXPoint mouseUpPt = mouseDownPt;
  1021.  
  1022.     [window disableFlushWindow];
  1023.  
  1024.     MiscTableWell *w1, *w2;
  1025.     [self setWells: &w1 : &w2 forPos: pos];
  1026.  
  1027.     NXZone* const z = [self zone];
  1028.     NXCoord pMin,pMax;
  1029.     NXImage* visCache = [[NXImage allocFromZone:z] init];
  1030.     NXImage* dragCache = [[NXImage allocFromZone:z] init];
  1031.     [self setVisibleCache: visCache min: &pMin max: &pMax];
  1032.     [self setDragCache: dragCache forPos: pos];
  1033.  
  1034.     NXSize size;
  1035.     [dragCache getSize: &size];
  1036.     NXCoord pLoc = info->getOffset( pos );
  1037.     NXCoord delta = [self offsetFromEvent: event] - pLoc;
  1038.  
  1039.     NXTrackingTimer* timer = 0;
  1040.     NXEvent lastEvent = *event;
  1041.     [scroll lockFocus];
  1042.     while (1)
  1043.         {
  1044.         NXPoint pt;
  1045.         NXRect rDrag = {{0,0},{0,0}};
  1046.         NXCoord const w = [self sizeWidth: &size];
  1047.         NXCoord const dw =
  1048.             dmin( dmin( dmin(w, pMax - pMin), pMax - pLoc), pLoc + w - pMin );
  1049.         BOOL const shouldDraw = (dw > 0.0);
  1050.         if (shouldDraw)
  1051.             {
  1052.             if (isHorz)
  1053.                 {
  1054.                 pt.x = dmax( pLoc, pMin );
  1055.                 pt.y = size.height;
  1056.                 if (pLoc < pMin)
  1057.                     rDrag.origin.x = (pMin - pLoc);
  1058.                 }
  1059.             else
  1060.                 {
  1061.                 pt.x = 0.0;
  1062.                 pt.y = dmax( pLoc, pMin ) + dw;
  1063.                 if (pLoc + w >= pMax)
  1064.                     rDrag.origin.y = pLoc + w - pMax;
  1065.                 }
  1066.             [scroll convertPoint: &pt fromView: self];
  1067.             [self setRect: &rDrag width: dw];
  1068.             [self setRect: &rDrag height: [self sizeHeight: &size]];
  1069.             [dragCache composite: NX_COPY fromRect: &rDrag toPoint: &pt];
  1070.             }
  1071.         [[window reenableFlushWindow] flushWindow];
  1072.  
  1073.         event = [NXApp getNextEvent: WANTED];
  1074.  
  1075.         [window disableFlushWindow];
  1076.         if (shouldDraw)
  1077.             {
  1078.             NXRect rVis = {{0,0},{0,0}};
  1079.             NXSize s; [visCache getSize: &s];
  1080.             NXCoord xTarg;
  1081.             if (isHorz)
  1082.                 {
  1083.                 xTarg = (pLoc < pMin ? 0.0 : pLoc - pMin);
  1084.                 }
  1085.             else
  1086.                 {
  1087.                 if (pLoc < pMin)
  1088.                     xTarg = s.height - dw;
  1089.                 else if (pLoc < pMax)
  1090.                     xTarg = pMax - pLoc - dw;
  1091.                 else
  1092.                     xTarg = 0.0;
  1093.                 }
  1094.             [self setRect: &rVis minX: xTarg];
  1095.             [self setRect: &rVis width: [self rectWidth: &rDrag]];
  1096.             [self setRect: &rVis height: [self rectHeight: &rDrag]];
  1097.             [visCache composite: NX_COPY fromRect: &rVis toPoint: &pt];
  1098.             }
  1099.  
  1100.         if (event == 0)
  1101.             break;
  1102.         if (event->type == NX_MOUSEUP)
  1103.             {
  1104.             mouseUpPt = event->location;
  1105.             [self convertPoint:&mouseUpPt fromView:0];
  1106.             break;
  1107.             }
  1108.         if (event->type != NX_TIMER)
  1109.             lastEvent = *event;
  1110.  
  1111.         NXCoord mLoc = [self offsetFromEvent: &lastEvent];
  1112.         if ((mLoc < pMin && pMin > 0.0) ||
  1113.             (mLoc > pMax && pMax < [self rectMaxX: &bounds]))
  1114.             {
  1115.             [self autoscroll: &lastEvent];
  1116.             [self setVisibleCache: visCache min: &pMin max: &pMax];
  1117.             mLoc = [self offsetFromEvent: &lastEvent];
  1118.             startTimer( timer );
  1119.             }
  1120.         else
  1121.             {
  1122.             stopTimer( timer );
  1123.             }
  1124.  
  1125.         pLoc = mLoc - delta;
  1126.         if (pLoc < pMin - [self sizeWidth: &size])
  1127.             pLoc = pMin - [self sizeWidth: &size];
  1128.         else if (pLoc > pMax)
  1129.             pLoc = pMax;
  1130.         }
  1131.  
  1132.     stopTimer( timer );
  1133.     [scroll unlockFocus];
  1134.     [self clearWells: &w1 : &w2];
  1135.     [visCache free];
  1136.     [dragCache free];
  1137.  
  1138.     MiscCoord_V const toPos = [self calcDrop:pos :&mouseDownPt :&mouseUpPt];
  1139.  
  1140.     if (toPos != pos)
  1141.         {
  1142.         BOOL const was_auto = [scroll isAutodisplay];
  1143.         [scroll setAutodisplay:NO];
  1144.         [self moveFrom: pos to: toPos];
  1145.         [self selectPos: toPos];
  1146.         [scroll border:[self borderType] slotDraggedFrom:pos to:toPos];
  1147.         [scroll setAutodisplay:was_auto];        // Will display if needed.
  1148.         }
  1149.     else
  1150.         {
  1151.         // Need to redisplay the slot that the wells were covering.
  1152.         MiscBorderType const b = [self borderType];
  1153.         int const phys_pos = [scroll border:b slotAtPosition:toPos];
  1154.         [scroll border:b drawSlotTitle:phys_pos];
  1155.         [scroll border:b drawSlot:phys_pos];
  1156.         }
  1157.  
  1158.     [[window reenableFlushWindow] flushWindow];
  1159.     return toPos;
  1160.     }
  1161.  
  1162.  
  1163. //-----------------------------------------------------------------------------
  1164. // - awaitDragEvent:inPos:
  1165. //-----------------------------------------------------------------------------
  1166. - (MiscCoord_V) awaitDragEvent: (NXEvent const*) event inPos: (MiscCoord_V) pos
  1167.     {
  1168.     MiscCoord_V toPos = pos;
  1169.     int const WANTED = (NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK);
  1170.     float const FOREVER = FLT_MAX;
  1171.     float const SLOP = 2.0;
  1172.     NXEvent mouseDown = *event;
  1173.     for (;;)
  1174.         {
  1175.         NXEvent peek;
  1176.         NXEvent* p = [NXApp peekNextEvent: WANTED into: &peek waitFor: FOREVER
  1177.                             threshold: NX_MODALRESPTHRESHOLD];
  1178.         if (p == 0 || p->type == NX_MOUSEUP)
  1179.             break;
  1180.         else if (p->location.x > mouseDown.location.x + SLOP ||
  1181.                  p->location.y > mouseDown.location.y + SLOP ||
  1182.                  p->location.x < mouseDown.location.x - SLOP ||
  1183.                  p->location.y < mouseDown.location.y - SLOP)
  1184.             {
  1185.             toPos = [self dragEvent: &mouseDown inPos: pos];
  1186.             break;
  1187.             }
  1188.         else
  1189.             [NXApp getNextEvent: NX_MOUSEDRAGGEDMASK];
  1190.         }
  1191.     return toPos;
  1192.     }
  1193.     
  1194.  
  1195.  
  1196. //=============================================================================
  1197. // SELECTION
  1198. //=============================================================================
  1199. //-----------------------------------------------------------------------------
  1200. // - selectionEvent:fromPos:
  1201. //-----------------------------------------------------------------------------
  1202. - (void) selectionEvent:(NXEvent const*)p fromPos:(MiscCoord_V)pos
  1203.     {
  1204.     BOOL doubleClicked = (p->data.mouse.click > 1);
  1205.  
  1206.     [tracker mouseDown: p atPos: pos];
  1207.     [scroll reflectSelection];
  1208.  
  1209.     NXTrackingTimer* timer = 0;
  1210.     startTimer( timer );
  1211.     NXEvent lastEvent = *p;
  1212.  
  1213.     while (1)
  1214.         {
  1215.         p = [NXApp getNextEvent:NX_MOUSEUPMASK |
  1216.                                 NX_MOUSEDRAGGEDMASK |
  1217.                                 NX_TIMERMASK ];
  1218.  
  1219.         if (p == 0 || p->type == NX_MOUSEUP)
  1220.             break;
  1221.         else if (p->type == NX_TIMER)
  1222.             [self autoscroll: &lastEvent];
  1223.         else
  1224.             lastEvent = *p;
  1225.  
  1226.         NXPoint new_loc = lastEvent.location;
  1227.         [self convertPoint:&new_loc fromView:0];
  1228.         MiscCoord_V new_pos = [self posForMousePt: &new_loc];
  1229.         if (new_pos != pos)
  1230.             {
  1231.             pos = new_pos;
  1232.             [tracker mouseDragged: p atPos: pos];
  1233.             [scroll reflectSelection];
  1234.             }
  1235.         }
  1236.  
  1237.     stopTimer( timer );
  1238.  
  1239.     [tracker mouseUp: p atPos: pos];
  1240.     [scroll reflectSelection];
  1241.     [self endTracking: pos];
  1242.  
  1243.     if (doubleClicked)
  1244.         [scroll sendDoubleActionIfEnabled];
  1245.     else
  1246.         [scroll sendActionIfEnabled];
  1247.     }
  1248.  
  1249.  
  1250.  
  1251. //=============================================================================
  1252. // MOUSE-EVENTS
  1253. //=============================================================================
  1254. //-----------------------------------------------------------------------------
  1255. // - acceptsFirstMouse
  1256. //-----------------------------------------------------------------------------
  1257. - (BOOL) acceptsFirstMouse
  1258.     {
  1259.     return YES;
  1260.     }
  1261.  
  1262.  
  1263. //-----------------------------------------------------------------------------
  1264. // - mouseDown:
  1265. //-----------------------------------------------------------------------------
  1266. - mouseDown:(NXEvent*)p
  1267.     {
  1268.     NXPoint evpt = p->location;
  1269.     [self convertPoint: &evpt fromView: 0];
  1270.     MiscCoord_V pos = [self posForMousePt: &evpt];
  1271.     int old_mask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
  1272.     MiscPixels x, delta_x;
  1273.  
  1274.     if ([self inHotZone:&evpt forPos:&pos atX:&x deltaX:&delta_x])
  1275.         {
  1276.         [self startTracking];
  1277.         [self selectPos:pos];
  1278.         MiscPixels finalWidth;
  1279.         BOOL doit;
  1280.         doit = [self resizeEvent:p inPos:pos atX:x deltaX:delta_x
  1281.                 finalWidth:&finalWidth];
  1282.         if (doit)
  1283.             {
  1284.             [window disableFlushWindow];
  1285.             [self setPos:pos width:finalWidth];
  1286.             [scroll border:[self borderType] slotResized:pos];
  1287.             [[window reenableFlushWindow] flushWindow];
  1288.             }
  1289.         [self endTracking:pos];
  1290.         [scroll sendActionIfEnabled];
  1291.         }
  1292.     else if (info->isDraggable() &&
  1293.         (info->isModifierDrag() == ((p->flags & NX_COMMANDMASK) != 0)))
  1294.         {
  1295.         [self startTracking];
  1296.         [self selectPos:pos];
  1297.         [window flushWindow];
  1298.         DPSFlush();
  1299.         MiscCoord_V toPos = [self awaitDragEvent:p inPos:pos];
  1300.         [self endTracking:toPos];
  1301.         [scroll sendActionIfEnabled];
  1302.         }
  1303.     else
  1304.         {
  1305.         assert( tracker != 0 );
  1306.         [self startTracking];
  1307.         [self selectionEvent: p fromPos: pos];
  1308.         }
  1309.  
  1310.     [window setEventMask:old_mask];
  1311.     return self;
  1312.     }
  1313.  
  1314. @end
  1315.