home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.bin / SourceCode / MiscKit1.2.6 / Examples / DragViewTest / MiscDragView.m < prev    next >
Encoding:
Text File  |  1994-06-17  |  14.6 KB  |  706 lines

  1. /**************************************************************************
  2.  * CLASS:        MiscDragView
  3.  *
  4.  *    See the header file for more information on this class.
  5.  *
  6.  * This object is included in the MiscKit by permission from the author
  7.  * and its use is governed by the MiscKit license, found in the file
  8.  * "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  9.  * for a list of all applicable permissions and restrictions.
  10.  **************************************************************************/
  11.  
  12. //#import <misckit/MiscString.h>
  13. #import <misckit/MiscDragView.h>
  14.  
  15.  
  16. /*
  17.  * A proper implementation of versioning. If you add ivars to the class (or
  18.  * just want to dork with the reading/writing) check out the comments tagged
  19.  * "Archiving: READ ME". BJM 5/24/94, adjusted 6/17/94.
  20.  */
  21.  
  22. /*
  23.  * **** Archiving: READ ME **** This is the current and defined version of the
  24.  * class. It is used to identify what data will be written and how that will
  25.  * happen. If the read/write stuff is modified AT ALL, this must be bumped up
  26.  * (I always bump by one) and the other comments must be followed. Failure to
  27.  * do so will result in palettes and nibs that cannot be read. BJM 5/24/94
  28.  */
  29. #define MISC_DRAG_VIEW_VERSION 0
  30.  
  31. @implementation MiscDragView
  32.  
  33. + initialize
  34. {
  35.     if (self == [MiscDragView class]) 
  36.     {
  37.         /*
  38.          * **** Archiving: READ ME **** After bumping the _VERSION, it is
  39.          * considered common practice to add a comment line indicating the new
  40.          * version number, date, and modifier. Optionally, the reason for the
  41.          * change. There is no need to modify the setVersion message. BJM
  42.          * 5/24/94 
  43.          */
  44.         // version 0: initial.  (bjm)
  45.         [[MiscDragView class] setVersion:MISC_DRAG_VIEW_VERSION];
  46.     }
  47.     
  48.     return self;
  49. }
  50.  
  51. - initFrame: (const NXRect *)frameRect
  52. {
  53.     [super initFrame: frameRect];
  54.  
  55.     [self setAllowSourceDragging: YES];
  56.     [self setAllowDestinationDragging: YES];
  57.     [self setAcceptForeignDrag: YES];
  58.     [self setAcceptLocalDrag: YES];
  59.     [self setAcceptSelfDrag: YES];
  60.     [self setRetainData: YES];
  61.  
  62.     [self setBorderType: NX_BEZEL];    
  63.     dragImage = nil;
  64.     theImage = nil;    
  65.     [self setDelegate: nil];
  66.  
  67.     return self;
  68. }
  69.  
  70.  
  71.  
  72. - awake
  73. {
  74.     [super awake];
  75.  
  76.     dragImage = nil;
  77.     
  78.     return self;
  79. }
  80.  
  81.  
  82.  
  83. - free
  84. {
  85.     if (theImage != nil)
  86.         [theImage free];
  87.         
  88.     return [super free];
  89. }
  90.  
  91.  
  92.  
  93. - setImage: (NXImage *)anImage
  94. {        
  95.     if ([self image] != nil)
  96.         [theImage free];
  97.     theImage = anImage;
  98.     
  99.     [theImage getSize: &imageSize];
  100.     [theImage setScalable: YES];
  101.     [theImage setDataRetained: YES];
  102.     
  103.     [self display];
  104.     return self;
  105. }
  106.  
  107.  
  108.  
  109. // Though the docs for NXImage say that initFromFile: does not need an
  110. // absolute pathname, I would recommend it. I had problems with it not 
  111. // finding images even when they were in the app wrapper
  112.  
  113. - setImageByFilename: (const char *)aFilename
  114. {
  115.     [self setImage: [ [NXImage alloc] initFromFile: aFilename] ];
  116.     return self;
  117. }
  118.  
  119.  
  120.  
  121. - (NXImage *)image
  122. {
  123.     return theImage;
  124. }
  125.  
  126.  
  127.  
  128.  
  129. // Border Type can be one of NX_BEZEL, NX_GROOVE, NX_LINE, or NX_NOBORDER,
  130. // same as the appkit's Box.
  131.  
  132. - setBorderType: (int)aType
  133. {
  134.     border = aType;
  135.     [self display];
  136.     return self;
  137. }
  138.  
  139.  
  140.  
  141. - (int)borderType
  142. {
  143.     return border;
  144. }
  145.  
  146.  
  147.  
  148. // Options that could apply to any subclassed DragView
  149.  
  150. - setAllowSourceDragging: (BOOL)aBool
  151. {
  152.     allowSourceDragging = aBool;
  153.     
  154.     return self;
  155. }
  156.  
  157.  
  158.  
  159. - (BOOL)allowSourceDragging
  160. {
  161.     return allowSourceDragging;
  162. }
  163.  
  164.  
  165.  
  166. - setAllowDestinationDragging: (BOOL)aBool
  167. {
  168.     allowDestinationDragging = aBool;
  169.     return self;
  170. }
  171.  
  172.  
  173.  
  174. - (BOOL)allowDestinationDragging
  175. {
  176.     return allowDestinationDragging;
  177. }
  178.  
  179.  
  180.  
  181. - setAcceptForeignDrag: (BOOL)aBool
  182. {
  183.     acceptForeignDrag = aBool;
  184.     return self;
  185. }
  186.  
  187.  
  188.  
  189. - (BOOL)acceptForeignDrag
  190. {
  191.     return acceptForeignDrag;
  192. }
  193.  
  194.  
  195.  
  196. - setAcceptLocalDrag: (BOOL)aBool
  197. {
  198.     acceptLocalDrag = aBool;
  199.     return self;
  200. }
  201.  
  202.  
  203.  
  204. - (BOOL)acceptLocalDrag
  205. {
  206.     return acceptLocalDrag;
  207. }
  208.  
  209.  
  210.  
  211. - setAcceptSelfDrag: (BOOL)aBool
  212. {
  213.     acceptSelfDrag = aBool;
  214.     return self;
  215. }
  216.  
  217.  
  218.  
  219. - (BOOL)acceptSelfDrag
  220. {
  221.     return acceptSelfDrag;
  222. }
  223.  
  224.  
  225.  
  226. - setRetainData: (BOOL)aBool
  227. {
  228.     retainData = aBool;
  229.     return self;
  230. }
  231.  
  232.  
  233.  
  234. - (BOOL)retainData
  235. {
  236.     return retainData;
  237. }
  238.  
  239.  
  240.  
  241. /*-------------------- methods to be the source of a dragging operation */
  242.  
  243. - mouseDown: (NXEvent *)theEvent
  244. {
  245.   NXPoint  zero = {0.0, 0.0};
  246.   NXPoint  offset = theEvent->location;
  247.   BOOL slide = YES;
  248.   id  dragPB = [Pasteboard newName: NXDragPboard];
  249.   
  250.      if ([self allowSourceDragging] == NO)
  251.         return [super mouseDown: theEvent]; 
  252.  
  253.     // if the overridden setupForSourceDrag returns yes continue
  254.     
  255.     if ([self setupForSourceDrag])
  256.     {    
  257.           [self convertPoint: &offset fromView: nil]; 
  258.  
  259.         // give the chance to change the offset and dragImage start point
  260.         
  261.         [self calculateDragPoint: &offset andOffset: &zero];
  262.         
  263.         if (dragImage != nil)
  264.         {            
  265.             if (![self retainData])
  266.             {
  267.                 slide = NO;
  268.                 
  269.                 // setting theImage to nil will make it disappear, giving
  270.                 // the impression that the data was not retained
  271.                 
  272.                 if (dragImage == theImage)
  273.                     theImage = nil;
  274.                 else
  275.                 {
  276.                     [theImage free];
  277.                     /*
  278.                      * Reset image var so that is not re-freed. BJM 5/24/94
  279.                      */
  280.                     theImage = nil;
  281.                 }
  282.             
  283.                 [self display];
  284.              }
  285.              
  286.             // send out the delegate message
  287.             
  288.             [self sourceDragInitiated: self];
  289.                             
  290.             // begin the drag session
  291.  
  292.             [NXApp preventWindowOrdering];            
  293.             
  294.             [self dragImage: dragImage at: &offset offset: &zero 
  295.                     event: theEvent    pasteboard: dragPB 
  296.                     source: self slideBack: slide];            
  297.          }
  298.      }
  299.           
  300.     return self;
  301. }
  302.  
  303.  
  304.  
  305. // This method should be overridden if you want to have some control
  306. // on where the dragged image is first placed, and how far it is offset
  307. // from the original mousedown (dragPoint).
  308.  
  309. - calculateDragPoint: (NXPoint *)dragPoint andOffset: (NXPoint *)offset
  310. {
  311.     return self;
  312. }
  313.  
  314.  
  315.  
  316. // A method that should be overridden in the subclass to put the information
  317. // on the desired pasteboard and select an image to drag.
  318.  
  319. - (BOOL)setupForSourceDrag
  320. {
  321.     return NO;
  322. }
  323.  
  324.  
  325.  
  326. // The following are methods from the NXSourceDraggingProtocol that are
  327. // here so they are easy to lookup.
  328.  
  329. - (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
  330. {
  331.     return NX_DragOperationAll;
  332. }
  333.  
  334.  
  335.  
  336. - draggedImage:(NXImage *)image beganAt:(NXPoint *)screenPoint
  337. {
  338.     return self;
  339. }
  340.  
  341.  
  342.  
  343. // Sends a "sourceDragFinished:" to the delegate if it responds.
  344.  
  345. - draggedImage:(NXImage *)image endedAt:(NXPoint *)screenPoint 
  346.         deposited:(BOOL)flag
  347. {
  348.     [self sourceDragFinished: flag];
  349.  
  350.     // clean up a little. Since the drag is done, free the dragImage 
  351.     // unless it is just a pointer to theImage (the image in the view).
  352.     
  353.     if (![self retainData])
  354.     {
  355.         [dragImage free];
  356.         /*
  357.          * Reset image var so that is not re-freed. BJM 5/29/94
  358.          */
  359.         dragImage = nil;
  360.     }
  361.     else
  362.         if (theImage == dragImage)
  363.             dragImage = nil;
  364.         else
  365.         {
  366.             [dragImage free];
  367.             
  368.             /*
  369.              * Reset image var so that is not re-freed. BJM 5/24/94
  370.              */
  371.             dragImage = nil;
  372.         }
  373.             
  374.     return self;
  375. }
  376.  
  377.  
  378.  
  379. /*-------------------- methods to be the destination of a dragging operation */
  380.  
  381. - (NXDragOperation)draggingEntered: sender
  382. {
  383.     if ([self allowDestinationDragging] == NO)
  384.         return NX_DragOperationNone;
  385.         
  386.      if ([self acceptSelfDrag] == NO && [sender draggingSource] == self)
  387.         return NX_DragOperationNone;
  388.         
  389.     if ([self acceptForeignDrag] == NO && [sender isDraggingSourceLocal] == NO)
  390.         return NX_DragOperationNone;
  391.         
  392.     if ([self acceptLocalDrag] == NO && [sender isDraggingSourceLocal] == YES)
  393.         return NX_DragOperationNone;
  394.     
  395.     // Send a "destinationDragInitiated:" to the delegate
  396.     
  397.     [self destinationDragInitiated: self];
  398.     
  399.     return NX_DragOperationCopy;
  400. }
  401.  
  402.  
  403.  
  404. - (NXDragOperation)draggingUpdated: sender
  405. {    
  406.     return [super draggingUpdated: sender]; 
  407. }
  408.  
  409.  
  410.  
  411. // Destination drag came to an end, but was not successful, so send a NO
  412. // to the delegate
  413.  
  414. - draggingExited:sender
  415. {
  416.     [self destinationDragFinished: NO];
  417.     return self;
  418. }
  419.  
  420.  
  421.  
  422. - (BOOL)prepareForDragOperation:sender
  423. {
  424.     return YES;
  425. }
  426.  
  427.  
  428.  
  429. - (BOOL)performDragOperation:sender
  430. {    
  431.     return YES;
  432. }
  433.  
  434.  
  435.  
  436. // Send the delegate a "destinationDragFinished" message
  437.  
  438. - concludeDragOperation:sender
  439. {
  440.     [self destinationDragFinished: YES];
  441.     return self;
  442. }
  443.  
  444.  
  445.  
  446. /*-------------------- methods to display, and other useful stuff */
  447.  
  448. - (BOOL)acceptsFirstMouse
  449. {
  450.     return YES;
  451. }
  452.  
  453.  
  454.  
  455. - (BOOL)shouldDelayWindowOrderingForEvent:(NXEvent *)theEvent
  456. {
  457.     return YES;
  458. }
  459.  
  460.  
  461.  
  462. // delegate methods
  463.  
  464. - delegate
  465. {
  466.     return delegate;
  467. }
  468.  
  469.  
  470.  
  471. - setDelegate: (id)theDelegate
  472. {
  473.     delegate = theDelegate;
  474.     return self;
  475. }
  476.  
  477.  
  478.  
  479. // Sent from "mouseDown" just before the dragging starts to take place
  480.  
  481. - sourceDragInitiated: view
  482. {
  483.     if ([delegate respondsTo: @selector(sourceDragInitiated:)])
  484.         [delegate sourceDragInitiated: view];
  485.     return self;
  486. }
  487.  
  488.  
  489.  
  490. // Sent when "draggedImage: endedAt: screenPoint: deposited:" is given 
  491. // control and success is whether the image was deposited in another
  492. // view somewhere
  493.  
  494. - sourceDragFinished: (BOOL)success
  495. {
  496.     if ([delegate respondsTo: @selector(sourceDragFinished:)])
  497.         [delegate sourceDragFinished: success];
  498.     return self;
  499. }
  500.  
  501.  
  502.  
  503. // Sent when "draggingEntered:" is given control
  504.  
  505. - destinationDragInitiated: view
  506. {
  507.     if ([delegate respondsTo: @selector(destinationDragInitiated:)])
  508.         [delegate destinationDragInitiated: view];
  509.     return self;
  510. }
  511.  
  512.  
  513.  
  514. // Sent when "concludeDragOperation:" is given control
  515.  
  516. - destinationDragFinished: (BOOL)success
  517. {
  518.     if ([delegate respondsTo: @selector(destinationDragFinished:)])
  519.         [delegate destinationDragFinished: success];
  520.     return self;
  521. }
  522.  
  523.  
  524.  
  525. // Draw the border, background color and the image if there is one.
  526. // I tried to add the scaling code to sizeTo:: but it did not seem
  527. // that it was called every time the view was resized (almost all the
  528. // time, but not good enough). So to be safe for now I lumped it all together.
  529.  
  530. - drawSelf: (const NXRect *)rects :(int)rectCount;
  531. {
  532.   NXPoint  offset;
  533.   NXRect  imageRect;
  534.  
  535.   
  536.     switch (border)
  537.     {
  538.         case NX_GROOVE:
  539.             NXDrawGroove (&bounds, rects);
  540.           break;
  541.         case NX_BEZEL:
  542.              NXDrawGrayBezel(&bounds, rects);
  543.           break;
  544.         case NX_LINE:
  545.             NXSetColor (NX_COLORBLACK);
  546.           NXFrameRect (&bounds);
  547.           break;
  548.           case NX_NOBORDER:
  549.           NXSetColor (NX_COLORLTGRAY);
  550.           NXRectFill (&bounds);
  551.             break;
  552.       }
  553.      
  554.     // set so the background color will not wipe the border
  555.     
  556.     imageRect.origin.x = bounds.origin.x + 2;
  557.        imageRect.origin.y = bounds.origin.y + 2;
  558.     imageRect.size.width = bounds.size.width - 4;
  559.     imageRect.size.height = bounds.size.height - 4;
  560.     
  561.     // if there is no image, then no reason to continue
  562.     
  563.     if ([self image] == nil)
  564.         return self;
  565.     
  566.     // use different offsets depending on if image scaled or not
  567.             
  568.     if (imageSize.width > bounds.size.width ||
  569.             imageSize.height > bounds.size.height)
  570.     {  
  571.       NXSize  scaledSize;
  572.       double xscale, yscale, scale;
  573.  
  574.         // scale the image and keep aspect ratio
  575.         
  576.          xscale = bounds.size.width / imageSize.width;
  577.         yscale = bounds.size.height / imageSize.height;
  578.         scale = ((xscale < yscale) ? xscale : yscale);
  579.         scaledSize.width = (imageSize.width * scale) - 2.0; 
  580.         scaledSize.height = (imageSize.height * scale) - 2.0;
  581.         
  582.         offset.x = (bounds.size.width - scaledSize.width) / 2;
  583.         offset.y = (bounds.size.height - scaledSize.height) / 2;
  584.         
  585.         if (xscale < yscale)        // so the image is not right on the edge
  586.             offset.x+=2.0; 
  587.         else
  588.             offset.y+=1.0;
  589.  
  590.         scaledSize.width -= 3.0;    // so when we move the offset,..
  591.         scaledSize.height -= 3.0;    // image will be basically centered
  592.         
  593.         [theImage setSize: &scaledSize];
  594.      }
  595.     else
  596.     { 
  597.         // no scaling needed
  598.         
  599.         offset = imageRect.origin;
  600.         offset.x += (imageRect.size.width - imageSize.width) / 2.0;
  601.         offset.y += (imageRect.size.height - imageSize.height) / 2.0;
  602.         [theImage setSize: &imageSize];
  603.      }
  604.  
  605.     [theImage composite: NX_SOVER toPoint: &offset];
  606.     return self;
  607. }
  608.  
  609.  
  610.  
  611. // Archiving methods
  612.  
  613. - read:(NXTypedStream *)stream
  614. {
  615.     int version;
  616.  
  617.     [super read:stream];
  618.     
  619.     version = NXTypedStreamClassVersion(stream, "MiscDragView");
  620.     
  621.     /*
  622.      * **** Archiving: READ ME **** This code (and its analogue in write:) is
  623.      * critical. When you bump MISC_DRAG_VIEW_VERSION, copy the whole _current_
  624.      * case ("case MISC_DRAG_VIEW_VERSION: ... break;"), and duplicate it.
  625.      * Change the "MISC_DRAG_VIEW_VERSION" in the old case to the OLD
  626.      * (pre-bump) version number. Now, dork the "new current" version into
  627.      * whatever you want. See how this code can now read EITHER version out of
  628.      * the typed stream?
  629.      *
  630.      * If you are adding yet another version, leave the previous versionS in
  631.      * place. That way you can still read archived objects that are more than
  632.      * one version old. Don't forget to take whatever actions are necessary to
  633.      * harmonize those old values. For example, if you converted an "int" ivar
  634.      * to "double", you'd need to (in the old version) to read the int version
  635.      * into a temp variable, and convert it in to the double var. BJM 5/24/94
  636.      */
  637.     switch (version)
  638.     {
  639.     case MISC_DRAG_VIEW_VERSION:
  640.         theImage = NXReadObject (stream);
  641.         NXReadSize (stream, &imageSize);
  642.         NXReadTypes (stream, "i", &border);    
  643.         
  644.         delegate = NXReadObject (stream);
  645.         NXReadTypes (stream, "c", &allowSourceDragging);
  646.         NXReadTypes (stream, "c", &allowDestinationDragging);
  647.         NXReadTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
  648.         NXReadTypes (stream, "cc", &acceptSelfDrag, &retainData);
  649.         break;
  650.  
  651.     default:
  652.         NXLogError("[%s %s] - unknown version of %s in typed stream",
  653.             [[self class] name], sel_getName(_cmd), 
  654.             [[MiscDragView class] name]);
  655.         break;
  656.     }
  657.  
  658.     return self;
  659. }
  660.  
  661. - write:(NXTypedStream *)stream
  662. {
  663.     [super write:stream];
  664.     
  665.     /*
  666.      * **** Archiving: READ ME **** Home stretch. Now (just like read:)
  667.      * duplicate the current case ("case MISC_DRAG_VIEW_VERSION: ... break;").
  668.      * Once again, change the "MISC_DRAG_VIEW_VERSION" of the first one to the
  669.      * OLD version number. Now adjust the new/current MISC_DRAG_VIEW_VERSION
  670.      * (remember, you've bumped it) to the new way of writing vars. See how
  671.      * this code (because the constant is in the switch statement) always
  672.      * writes out ONLY the current version, but leaves the old version(s)
  673.      * around to posterity. DO NOT DELETE THE OLD VERSIONS. Leave them to
  674.      * clutter up the world. BJM 5/24/94  
  675.      */
  676.     switch (MISC_DRAG_VIEW_VERSION)
  677.     {
  678.     case MISC_DRAG_VIEW_VERSION:
  679.         NXWriteObject (stream, theImage);
  680.         NXWriteSize (stream, &imageSize);    
  681.         NXWriteTypes (stream, "i", &border);
  682.     
  683.         NXWriteObjectReference (stream, delegate);
  684.         NXWriteTypes (stream, "c", &allowSourceDragging);
  685.         NXWriteTypes (stream, "c", &allowDestinationDragging);
  686.         NXWriteTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
  687.         NXWriteTypes (stream, "cc", &acceptSelfDrag, &retainData);
  688.         break;
  689.  
  690.     default:
  691.         NXLogError("[%s %s] - unknown version of %s in typed stream",
  692.             [[self class] name], sel_getName(_cmd), [[self class] name]);
  693.         break;
  694.     }
  695.  
  696.     return self;
  697. }
  698.  
  699. - (const char *)getInspectorClassName
  700. {
  701.     return "MiscDVInspector";
  702. }
  703.  
  704.  
  705. @end
  706.