home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1994 June / NEBULA_SE.ISO / SourceCode / MiscKit / Palettes / MiscDragViews / MiscViews.subproj / MiscDragView.m < prev    next >
Encoding:
Text File  |  1994-03-17  |  11.0 KB  |  606 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. @implementation MiscDragView
  17.  
  18. - initFrame: (const NXRect *)frameRect
  19. {
  20.     [super initFrame: frameRect];
  21.  
  22.     [self setAllowSourceDragging: YES];
  23.     [self setAllowDestinationDragging: YES];
  24.     [self setAcceptForeignDrag: YES];
  25.     [self setAcceptLocalDrag: YES];
  26.     [self setAcceptSelfDrag: YES];
  27.     [self setRetainData: YES];
  28.  
  29.     [self setBorderType: NX_BEZEL];    
  30.     dragImage = nil;
  31.     theImage = nil;    
  32.     [self setDelegate: nil];
  33.  
  34.     return self;
  35. }
  36.  
  37.  
  38.  
  39. - awake
  40. {
  41.     [super awake];
  42.  
  43.     dragImage = nil;
  44.     
  45.     return self;
  46. }
  47.  
  48.  
  49.  
  50. - free
  51. {
  52.     if (theImage != nil)
  53.         [theImage free];
  54.         
  55.     return [super free];
  56. }
  57.  
  58.  
  59.  
  60. - setImage: (NXImage *)anImage
  61. {        
  62.     if ([self image] != nil)
  63.         [theImage free];
  64.     theImage = anImage;
  65.     
  66.     [theImage getSize: &imageSize];
  67.     [theImage setScalable: YES];
  68.     [theImage setDataRetained: YES];
  69.     
  70.     [self display];
  71.     return self;
  72. }
  73.  
  74.  
  75.  
  76. // Though the docs for NXImage say that initFromFile: does not need an
  77. // absolute pathname, I would recommend it. I had problems with it not 
  78. // finding images even when they were in the app wrapper
  79.  
  80. - setImageByFilename: (char *)aFilename
  81. {
  82.     [self setImage: [ [NXImage alloc] initFromFile: aFilename] ];
  83.     return self;
  84. }
  85.  
  86.  
  87.  
  88. - (NXImage *)image
  89. {
  90.     return theImage;
  91. }
  92.  
  93.  
  94.  
  95.  
  96. // Border Type can be one of NX_BEZEL, NX_GROOVE, NX_LINE, or NX_NOBORDER,
  97. // same as the appkit's Box.
  98.  
  99. - setBorderType: (int)aType
  100. {
  101.     border = aType;
  102.     [self display];
  103.     return self;
  104. }
  105.  
  106.  
  107.  
  108. - (int)borderType
  109. {
  110.     return border;
  111. }
  112.  
  113.  
  114.  
  115. // Options that could apply to any subclassed DragView
  116.  
  117. - setAllowSourceDragging: (BOOL)aBool
  118. {
  119.     allowSourceDragging = aBool;
  120.     
  121.     return self;
  122. }
  123.  
  124.  
  125.  
  126. - (BOOL)allowSourceDragging
  127. {
  128.     return allowSourceDragging;
  129. }
  130.  
  131.  
  132.  
  133. - setAllowDestinationDragging: (BOOL)aBool
  134. {
  135.     allowDestinationDragging = aBool;
  136.     return self;
  137. }
  138.  
  139.  
  140.  
  141. - (BOOL)allowDestinationDragging
  142. {
  143.     return allowDestinationDragging;
  144. }
  145.  
  146.  
  147.  
  148. - setAcceptForeignDrag: (BOOL)aBool
  149. {
  150.     acceptForeignDrag = aBool;
  151.     return self;
  152. }
  153.  
  154.  
  155.  
  156. - (BOOL)acceptForeignDrag
  157. {
  158.     return acceptForeignDrag;
  159. }
  160.  
  161.  
  162.  
  163. - setAcceptLocalDrag: (BOOL)aBool
  164. {
  165.     acceptLocalDrag = aBool;
  166.     return self;
  167. }
  168.  
  169.  
  170.  
  171. - (BOOL)acceptLocalDrag
  172. {
  173.     return acceptLocalDrag;
  174. }
  175.  
  176.  
  177.  
  178. - setAcceptSelfDrag: (BOOL)aBool
  179. {
  180.     acceptSelfDrag = aBool;
  181.     return self;
  182. }
  183.  
  184.  
  185.  
  186. - (BOOL)acceptSelfDrag
  187. {
  188.     return acceptSelfDrag;
  189. }
  190.  
  191.  
  192.  
  193. - setRetainData: (BOOL)aBool
  194. {
  195.     retainData = aBool;
  196.     return self;
  197. }
  198.  
  199.  
  200.  
  201. - (BOOL)retainData
  202. {
  203.     return retainData;
  204. }
  205.  
  206.  
  207.  
  208. /*-------------------- methods to be the source of a dragging operation */
  209.  
  210. - mouseDown: (NXEvent *)theEvent
  211. {
  212.   NXPoint  zero = {0.0, 0.0};
  213.   NXPoint  offset = theEvent->location;
  214.   BOOL slide = YES;
  215.   id  dragPB = [Pasteboard newName: NXDragPboard];
  216.   
  217.      if ([self allowSourceDragging] == NO)
  218.         return [super mouseDown: theEvent]; 
  219.  
  220.     // if the overridden setupForSourceDrag returns yes continue
  221.     
  222.     if ([self setupForSourceDrag])
  223.     {    
  224.           [self convertPoint: &offset fromView: nil]; 
  225.  
  226.         // give the chance to change the offset and dragImage start point
  227.         
  228.         [self calculateDragPoint: &offset andOffset: &zero];
  229.         
  230.         if (dragImage != nil)
  231.         {            
  232.             if (![self retainData])
  233.             {
  234.                 slide = NO;
  235.                 
  236.                 // setting theImage to nil will make it disappear, giving
  237.                 // the impression that the data was not retained
  238.                 
  239.                 if (dragImage == theImage)
  240.                     theImage = nil;
  241.                 else
  242.                     [theImage free];
  243.             
  244.                 [self display];
  245.              }
  246.              
  247.             // send out the delegate message
  248.             
  249.             [self sourceDragInitiated: self];
  250.                             
  251.             // begin the drag session
  252.  
  253.             [NXApp preventWindowOrdering];            
  254.             
  255.             [self dragImage: dragImage at: &offset offset: &zero 
  256.                     event: theEvent    pasteboard: dragPB 
  257.                     source: self slideBack: slide];            
  258.          }
  259.      }
  260.           
  261.     return self;
  262. }
  263.  
  264.  
  265.  
  266. // This method should be overridden if you want to have some control
  267. // on where the dragged image is first placed, and how far it is offset
  268. // from the original mousedown (dragPoint).
  269.  
  270. - calculateDragPoint: (NXPoint *)dragPoint andOffset: (NXPoint *)offset
  271. {
  272.     return self;
  273. }
  274.  
  275.  
  276.  
  277. // A method that should be overridden in the subclass to put the information
  278. // on the desired pasteboard and select an image to drag.
  279.  
  280. - (BOOL)setupForSourceDrag
  281. {
  282.     return NO;
  283. }
  284.  
  285.  
  286.  
  287. // The following are methods from the NXSourceDraggingProtocol that are
  288. // here so they are easy to lookup.
  289.  
  290. - (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
  291. {
  292.     return NX_DragOperationAll;
  293. }
  294.  
  295.  
  296.  
  297. - draggedImage:(NXImage *)image beganAt:(NXPoint *)screenPoint
  298. {
  299.     return self;
  300. }
  301.  
  302.  
  303.  
  304. // Sends a "sourceDragFinished:" to the delegate if it responds.
  305.  
  306. - draggedImage:(NXImage *)image endedAt:(NXPoint *)screenPoint 
  307.         deposited:(BOOL)flag
  308. {
  309.     [self sourceDragFinished: flag];
  310.  
  311.     // clean up a little. Since the drag is done, free the dragImage 
  312.     // unless it is just a pointer to theImage (the image in the view).
  313.     
  314.     if (![self retainData])
  315.         [dragImage free];
  316.     else
  317.         if (theImage == dragImage)
  318.             dragImage = nil;
  319.         else
  320.             [dragImage free];
  321.             
  322.     return self;
  323. }
  324.  
  325.  
  326.  
  327. /*-------------------- methods to be the destination of a dragging operation */
  328.  
  329. - (NXDragOperation)draggingEntered: sender
  330. {
  331.     if ([self allowDestinationDragging] == NO)
  332.         return NX_DragOperationNone;
  333.         
  334.      if ([self acceptSelfDrag] == NO && [sender draggingSource] == self)
  335.         return NX_DragOperationNone;
  336.         
  337.     if ([self acceptForeignDrag] == NO && [sender isDraggingSourceLocal] == NO)
  338.         return NX_DragOperationNone;
  339.         
  340.     if ([self acceptLocalDrag] == NO && [sender isDraggingSourceLocal] == YES)
  341.         return NX_DragOperationNone;
  342.     
  343.     // Send a "destinationDragInitiated:" to the delegate
  344.     
  345.     [self destinationDragInitiated: self];
  346.     
  347.     return NX_DragOperationCopy;
  348. }
  349.  
  350.  
  351.  
  352. - (NXDragOperation)draggingUpdated: sender
  353. {    
  354.     return [super draggingUpdated: sender]; 
  355. }
  356.  
  357.  
  358.  
  359. // Destination drag came to an end, but was not successful, so send a NO
  360. // to the delegate
  361.  
  362. - draggingExited:sender
  363. {
  364.     [self destinationDragFinished: NO];
  365.     return self;
  366. }
  367.  
  368.  
  369.  
  370. - (BOOL)prepareForDragOperation:sender
  371. {
  372.     return YES;
  373. }
  374.  
  375.  
  376.  
  377. - (BOOL)performDragOperation:sender
  378. {    
  379.     return YES;
  380. }
  381.  
  382.  
  383.  
  384. // Send the delegate a "destinationDragFinished" message
  385.  
  386. - concludeDragOperation:sender
  387. {
  388.     [self destinationDragFinished: YES];
  389.     return self;
  390. }
  391.  
  392.  
  393.  
  394. /*-------------------- methods to display, and other useful stuff */
  395.  
  396. - (BOOL)acceptsFirstMouse
  397. {
  398.     return YES;
  399. }
  400.  
  401.  
  402.  
  403. - (BOOL)shouldDelayWindowOrderingForEvent:(NXEvent *)theEvent
  404. {
  405.     return YES;
  406. }
  407.  
  408.  
  409.  
  410. // delegate methods
  411.  
  412. - delegate
  413. {
  414.     return delegate;
  415. }
  416.  
  417.  
  418.  
  419. - setDelegate: (id)theDelegate
  420. {
  421.     delegate = theDelegate;
  422.     return self;
  423. }
  424.  
  425.  
  426.  
  427. // Sent from "mouseDown" just before the dragging starts to take place
  428.  
  429. - sourceDragInitiated: view
  430. {
  431.     if ([delegate respondsTo: @selector(sourceDragInitiated:)])
  432.         [delegate sourceDragInitiated: view];
  433.     return self;
  434. }
  435.  
  436.  
  437.  
  438. // Sent when "draggedImage: endedAt: screenPoint: deposited:" is given 
  439. // control and success is whether the image was deposited in another
  440. // view somewhere
  441.  
  442. - sourceDragFinished: (BOOL)success
  443. {
  444.     if ([delegate respondsTo: @selector(sourceDragFinished:)])
  445.         [delegate sourceDragFinished: success];
  446.     return self;
  447. }
  448.  
  449.  
  450.  
  451. // Sent when "draggingEntered:" is given control
  452.  
  453. - destinationDragInitiated: view
  454. {
  455.     if ([delegate respondsTo: @selector(destinationDragInitiated:)])
  456.         [delegate destinationDragInitiated: view];
  457.     return self;
  458. }
  459.  
  460.  
  461.  
  462. // Sent when "concludeDragOperation:" is given control
  463.  
  464. - destinationDragFinished: (BOOL)success
  465. {
  466.     if ([delegate respondsTo: @selector(destinationDragFinished:)])
  467.         [delegate destinationDragFinished: success];
  468.     return self;
  469. }
  470.  
  471.  
  472.  
  473. // Draw the border, background color and the image if there is one.
  474. // I tried to add the scaling code to sizeTo:: but it did not seem
  475. // that it was called every time the view was resized (almost all the
  476. // time, but not good enough). So to be safe for now I lumped it all together.
  477.  
  478. - drawSelf: (const NXRect *)rects :(int)rectCount;
  479. {
  480.   NXPoint  offset;
  481.   NXRect  imageRect;
  482.  
  483.   
  484.     switch (border)
  485.     {
  486.         case NX_GROOVE:
  487.             NXDrawGroove (&bounds, rects);
  488.           break;
  489.         case NX_BEZEL:
  490.              NXDrawGrayBezel(&bounds, rects);
  491.           break;
  492.         case NX_LINE:
  493.             NXSetColor (NX_COLORBLACK);
  494.           NXFrameRect (&bounds);
  495.           break;
  496.           case NX_NOBORDER:
  497.           NXSetColor (NX_COLORLTGRAY);
  498.           NXRectFill (&bounds);
  499.             break;
  500.       }
  501.      
  502.     // set so the background color will not wipe the border
  503.     
  504.     imageRect.origin.x = bounds.origin.x + 2;
  505.        imageRect.origin.y = bounds.origin.y + 2;
  506.     imageRect.size.width = bounds.size.width - 4;
  507.     imageRect.size.height = bounds.size.height - 4;
  508.     
  509.     // if there is no image, then no reason to continue
  510.     
  511.     if ([self image] == nil)
  512.         return self;
  513.     
  514.     // use different offsets depending on if image scaled or not
  515.             
  516.     if (imageSize.width > bounds.size.width ||
  517.             imageSize.height > bounds.size.height)
  518.     {  
  519.       NXSize  scaledSize;
  520.       double xscale, yscale, scale;
  521.  
  522.         // scale the image and keep aspect ratio
  523.         
  524.          xscale = bounds.size.width / imageSize.width;
  525.         yscale = bounds.size.height / imageSize.height;
  526.         scale = ((xscale < yscale) ? xscale : yscale);
  527.         scaledSize.width = (imageSize.width * scale) - 2.0; 
  528.         scaledSize.height = (imageSize.height * scale) - 2.0;
  529.         
  530.         offset.x = (bounds.size.width - scaledSize.width) / 2;
  531.         offset.y = (bounds.size.height - scaledSize.height) / 2;
  532.         
  533.         if (xscale < yscale)        // so the image is not right on the edge
  534.             offset.x+=2.0; 
  535.         else
  536.             offset.y+=1.0;
  537.  
  538.         scaledSize.width -= 3.0;    // so when we move the offset,..
  539.         scaledSize.height -= 3.0;    // image will be basically centered
  540.         
  541.         [theImage setSize: &scaledSize];
  542.      }
  543.     else
  544.     { 
  545.         // no scaling needed
  546.         
  547.         offset = imageRect.origin;
  548.         offset.x += (imageRect.size.width - imageSize.width) / 2.0;
  549.         offset.y += (imageRect.size.height - imageSize.height) / 2.0;
  550.         [theImage setSize: &imageSize];
  551.      }
  552.  
  553.     [theImage composite: NX_SOVER toPoint: &offset];
  554.     return self;
  555. }
  556.  
  557.  
  558.  
  559. // Archiving methods
  560.  
  561. - read: (NXTypedStream *)stream
  562. {
  563.     [super read: stream];
  564.     
  565.     theImage = NXReadObject (stream);
  566.     NXReadSize (stream, &imageSize);
  567.     NXReadTypes (stream, "i", &border);    
  568.     
  569.     delegate = NXReadObject (stream);
  570.     NXReadTypes (stream, "c", &allowSourceDragging);
  571.     NXReadTypes (stream, "c", &allowDestinationDragging);
  572.     NXReadTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
  573.     NXReadTypes (stream, "cc", &acceptSelfDrag, &retainData);
  574.     
  575.     return self;
  576. }
  577.  
  578.  
  579.  
  580. - write: (NXTypedStream *)stream
  581. {
  582.     [super write: stream];
  583.     
  584.     NXWriteObject (stream, theImage);
  585.     NXWriteSize (stream, &imageSize);    
  586.     NXWriteTypes (stream, "i", &border);
  587.  
  588.     NXWriteObjectReference (stream, delegate);
  589.     NXWriteTypes (stream, "c", &allowSourceDragging);
  590.     NXWriteTypes (stream, "c", &allowDestinationDragging);
  591.     NXWriteTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
  592.     NXWriteTypes (stream, "cc", &acceptSelfDrag, &retainData);
  593.     
  594.     return self;
  595. }
  596.  
  597.  
  598.  
  599. - (const char *)getInspectorClassName
  600. {
  601.     return "MiscDVInspector";
  602. }
  603.  
  604.  
  605. @end
  606.