//
//  Lynkeos
//  $Id: MyImageView.m 590 2018-12-13 23:11:15Z j-etienne $
//
//  Created by Jean-Etienne LAMIAUD on Wed Sep 24 2003.
//  Copyright (c) 2003-2018. Jean-Etienne LAMIAUD
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//

#include <math.h>

#include "ProcessStackManager.h"
#include "MyImageView.h"

#define K_MAX_ZOOM 4.0

static const double MM_LN_10 = -M_LN10;

/*!
 * @abstract Zoom management part of MyImageView.
 */
@interface MyImageView(Zoom)

/*!
 * @method applyZoom:from:
 * @abstract Set the zoom factor to the required value.
 * @param newZoom The zoom factor to apply
 * @param sender The object asking for zoom
 */
- (void) applyZoom :(double)newZoom from:(id)sender ;

/*!
 * @method stepZoom:
 * @abstract Step the zoom factor to the nearest half integer power of two.
 * @param step The step to apply to the log2 of the zoom factor.
 */
- (void) stepZoom :(double)step;
@end

@implementation MyImageView(Zoom)

- (void) applyZoom :(double)newZoom from:(id)sender
{
   NSRect newFrame, newBounds = _canvasRect;
   NSRect visible = [self visibleRect];
   NSRect enclosing = [[self superview] bounds];

   // Adjust the enclosing bounds to the intended zoom
   enclosing.origin.x /= newZoom;
   enclosing.origin.y /= newZoom;
   enclosing.size.width /= newZoom;
   enclosing.size.height /= newZoom;

   // Set the bounds to the largest between image rect and enclosing NSClipView bounds
   if (newBounds.origin.x > enclosing.origin.x)
   {
      newBounds.size.width += newBounds.origin.x - enclosing.origin.x;
      newBounds.origin.x = enclosing.origin.x;
   }
   if ((newBounds.origin.x + newBounds.size.width) < (enclosing.origin.x + enclosing.size.width))
      newBounds.size.width  = enclosing.origin.x + enclosing.size.width - newBounds.origin.x;
   if (newBounds.origin.y > enclosing.origin.y)
   {
      newBounds.size.height += newBounds.origin.y - enclosing.origin.y;
      newBounds.origin.y = enclosing.origin.y;
   }
   if ((newBounds.origin.y + newBounds.size.height) < (enclosing.origin.y + enclosing.size.height))
      newBounds.size.height  = enclosing.origin.y + enclosing.size.height - newBounds.origin.y;

   // Apply zoom
   if ( newBounds.size.width != 0 )
   {
      newFrame.size.width = newBounds.size.width * newZoom;
      newFrame.origin.x = newBounds.origin.x * newZoom;
   }
   else
   {	// NSView don't like null sizes
      newFrame.size.width = 1;
      newFrame.origin.x = 0;
      newBounds.size.width = 1;
      newBounds.origin.x = 0;
   }

   if ( newBounds.size.height != 0 )
   {
      newFrame.size.height = newBounds.size.height * newZoom;
      newFrame.origin.y = newBounds.origin.y * newZoom;
   }
   else
   {	// NSView don't like null sizes
      newFrame.size.height = 1;
      newFrame.origin.y = 0;
      newBounds.size.height = 1;
      newBounds.origin.y = 0;
   }

   [self setFrameSize:newFrame.size];
   [self setFrameOrigin:newFrame.origin];
   [self setBoundsSize:newBounds.size];
   [self setBoundsOrigin:newBounds.origin];

   if ( newZoom != _zoom )
   {
      // Adjust scroll to keep center still
      if ( _canvasRect.size.width != 0 && _canvasRect.size.height != 0 )
      {
         visible.origin.x += (1 - _zoom/newZoom)*visible.size.width/2;
         if ( visible.origin.x < 0 )
            visible.origin.x = 0;
         visible.origin.y += (1 - _zoom/newZoom)*visible.size.height/2;
         if ( visible.origin.y < 0 )
            visible.origin.y = 0;
         visible.size.width *= _zoom/newZoom;
         visible.size.height *= _zoom/newZoom;

         [self scrollRectToVisible:visible];
      }

      _zoom = newZoom;
      if ( sender != _zoomField )
         [_zoomField setDoubleValue:_zoom*100.0];
      if ( sender != _zoomSlider )
         [_zoomSlider setDoubleValue:log(_zoom)/log(K_MAX_ZOOM)];

      [[NSNotificationCenter defaultCenter] postNotificationName: LynkeosImageViewZoomDidChangeNotification
                                                          object: self];
   }

   // Make me redraw
   [self setNeedsDisplay:YES];
}

- (void) stepZoom :(double)step
{
   double z = log(_zoom)/log(2);

   // Get the wanted half integer value
   if ( step < 0.0 && z > 0.0 )
      z += 0.49999999;
   else if ( step > 0.0 && z < 0.0 )
      z -= 0.49999999;

   z = (double)((int)((z+step)*2))/2.0;
   z = exp(log(2)*z);

   [self applyZoom: z from:nil];
}
@end

@implementation MyImageView

// Initializations and allocation stuff
- (id)initWithFrame:(NSRect)frameRect
{
   LynkeosIntegerRect nowhere = { {0,0}, {0,0} };

   if ( (self = [super initWithFrame:frameRect]) == nil )
      return( self );

   _selectionDelegate = nil;
   _item = nil;
   _itemSequenceNumber = 0;
   _itemSize = LynkeosMakeIntegerSize(0, 0);
   _imageTransform = nil;
   _imageRep = nil;

   _zoom = 1.0;

   _selectionMode = NoSelection;
   _savedSelectionMode = NoSelection;
   _freezeCounter = 0;
   _selectionOrigin = nowhere.origin;
   _lastPoint = nowhere.origin;
   _selection = [[NSMutableArray array] retain];
   _inProgressSelection = nowhere;
   _currentSelectionIndex = NSNotFound;
   _previousSelectionIndex = NSNotFound;
   _autoscrollTimer = nil;

   [self initCursors];

    return self;
}

- (void) dealloc
{
   if ( _imageRep != nil )
      [_imageRep release];
   if ( _item != nil )
      [_item release];
   if ( _imageTransform != nil )
      [_imageTransform release];

   [_selection release];
   [_crossCursor release];
   [_leftCursor release];
   [_rightCursor release];
   [_topCursor release];
   [_bottomCursor release];
   [_topLeftCursor release];
   [_topRightCursor release];
   [_bottomLeftCursor release];
   [_bottomRightCursor release];
   [_insideCursor release];

   [super dealloc];
}

- (void) awakeFromNib
{
   [_blackText setEnabled:NO];
   [_whiteText setEnabled:NO];
   [_blackWhiteSlider setEnabled:NO];
   [_gammaText setEnabled:NO];
   [_gammaSlider setEnabled:NO];
   [_blackText setStringValue:@""];
   [_whiteText setStringValue:@""];
   [_gammaText setStringValue:@""];   
}

// Image and zoom
- (IBAction)doZoom:(id)sender
{
   double z;

   if ( sender == _zoomSlider )
      z = exp(log(K_MAX_ZOOM)*[sender doubleValue]);
   else
      z = [sender doubleValue]/100.0;

   [self applyZoom: z from:sender];
}

- (IBAction)moreZoom:(id)sender
{
   if ( _zoom < K_MAX_ZOOM )
      [self stepZoom:0.5];
}

- (IBAction)lessZoom:(id)sender
{
   if ( _zoom > 1.0/K_MAX_ZOOM )
      [self stepZoom:-0.5];	// To be improved in stepZoom
}

- (IBAction) blackWhiteChange :(id)sender
{
   // Reconcile slider and text fields
   double black = 0, white = 255;
   if ( sender == _blackWhiteSlider )
   {
      black = [sender doubleLoValue];
      [_blackText setDoubleValue:black];
      white = [sender doubleHiValue];
      [_whiteText setDoubleValue:white];
   }
   else if ( sender == _blackText )
   {
      black = [sender doubleValue];
      white = [_blackWhiteSlider doubleHiValue];
      if ( black > white )
      {
         black = white;
         [sender setDoubleValue:black];
      }
      if ( black < [_blackWhiteSlider minValue] )
         [_blackWhiteSlider setMinValue:black];
      [_blackWhiteSlider setDoubleLoValue:black];
   }
   else if ( sender == _whiteText )
   {
      black = [_blackWhiteSlider doubleLoValue];
      white = [sender doubleValue];
      if ( white < black )
      {
         white = black;
         [sender setDoubleValue:white];
      }
      if ( white > [_blackWhiteSlider maxValue] )
         [_blackWhiteSlider setMaxValue:white];
      [_blackWhiteSlider setDoubleHiValue:white];
   }
   else
      NSAssert(NO,@"Unknown control in blackWhiteChange");

   // Set the levels in the item
   [_item setBlackLevel:black whiteLevel:white gamma:[_gammaText doubleValue]];

   // Refresh the image
   [self updateImage];
   // Make me redraw
   [self setNeedsDisplay:YES];
}

- (IBAction) gammaChange :(id)sender
{
   double gammaCorrect = 1.0;

   // Reconcile controls
   if ( sender == _gammaSlider )
   {
      gammaCorrect = exp(MM_LN_10*[sender doubleValue]);
      [_gammaText setDoubleValue:gammaCorrect];
   }
   else if ( sender == _gammaText )
   {
      gammaCorrect = [sender doubleValue];
      [_gammaSlider setDoubleValue:log(gammaCorrect)/MM_LN_10];
   }
   else
      NSAssert( NO, @"Unknown gamma control" );

   // Set the levels in the item
   [_item setBlackLevel:[_blackText doubleValue]
             whiteLevel:[_whiteText doubleValue]
                  gamma:gammaCorrect];

   // Refresh the image
   [self updateImage];
   // Make me redraw
   [self setNeedsDisplay:YES];
}

- (void) displayItem:(id <LynkeosProcessableItem>)item
{
   [self displayItem:item withTransform:[NSAffineTransform transform]];
}

- (void) displayItem:(id <LynkeosProcessableItem>)item
       withTransform:(NSAffineTransform*)transform
{
   NSAffineTransform *newTransform
      = [[[NSAffineTransform alloc] initWithTransform:transform] autorelease];
   if ( item != nil )
   {
      // Get the align transform if any
      id <LynkeosViewAlignResult> res = (id <LynkeosViewAlignResult>)
         [item getProcessingParameterWithRef:LynkeosAlignResultRef
                               forProcessing:LynkeosAlignRef];
      if ( res != nil )
         [newTransform prependTransform:[res alignTransform]];
   }

   // Avoid useless updates
   if ( item == _item &&
       ( item == nil ||
        ( [item getSequenceNumber] == _itemSequenceNumber &&
          [_imageTransform isEqual:newTransform] ) ) )
      return;

   // Save the parameters
   if ( _imageTransform != nil )
      [_imageTransform release];
   _imageTransform = newTransform;
   if ( _imageTransform != nil )
      [_imageTransform retain];

   if ( _item != item )
   {
      if ( _item != nil )
         [_item release];
      _itemSequenceNumber = 0;
      _item = item;
      if ( _item != nil )
         [_item retain];
   }
   if ( _item != nil )
   {
      _itemSequenceNumber = [item getSequenceNumber];
   }

   // Display that new image
   [self updateImage];
}

- (void) updateImage
{
   NSImage *image = nil;

   // Cleanup before else
   _canvasRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
   if ( _imageRep != nil )
   {
      [_imageRep release];
      _imageRep = nil;
   }

   // Get the new image
   if ( _item != nil )
   {
      const LynkeosIntegerSize s = [_item imageSize];

      // Adjust the view frame if the image size has changed
      if (_itemSize.width != s.width || _itemSize.height != s.height)
         _itemSize = s;

      image = [_item getNSImage];
      if (image != nil)
      {
         NSRect r = {{0.0, 0.0}, {0.0, 0.0}};
         CGFloat x, y;

         r.size = [image size];
         _imageRep = [[image bestRepresentationForRect:r context:nil hints:nil] retain];

         _canvasRect = NSMakeRect(0.0, 0.0, (CGFloat)_itemSize.width, (CGFloat)_itemSize.height);

         // Compute the rectangle wich encloses the transformed image (rotated, scaled)
         for ( y = 0.0; y <= _canvasRect.size.height; y +=  _canvasRect.size.height )
         {
            for ( x = 0.0; x <= _canvasRect.size.width; x+= _canvasRect.size.width )
            {
               NSPoint p = [_imageTransform transformPoint:NSMakePoint(x, y)];

               if ( p.x < _canvasRect.origin.x )
               {
                  _canvasRect.size.width += (_canvasRect.origin.x - p.x);
                  _canvasRect.origin.x = p.x;
               }
               else if ( p.x > _canvasRect.origin.x + _canvasRect.size.width )
                  _canvasRect.size.width = p.x - _canvasRect.origin.x;
               if ( p.y < _canvasRect.origin.y )
               {
                  _canvasRect.size.height += (_canvasRect.origin.y - p.y);
                  _canvasRect.origin.y = p.y;
               }
               else if ( p.y > _canvasRect.origin.y + _canvasRect.size.height )
                  _canvasRect.size.height = p.y - _canvasRect.origin.y;
            }
         }
      }
   }

   double vmin, vmax, black, white, gamma;
   BOOL validRange = NO, validLevels = NO;
   if ( _item != nil )
   {
      validRange = [_item isProcessed]
                   && [_item getMinLevel:&vmin maxLevel:&vmax];
      validLevels= [_item getBlackLevel:&black whiteLevel:&white gamma:&gamma];
   }

   [_blackText setEnabled:(validRange && validLevels)];
   [_whiteText setEnabled:(validRange && validLevels)];
   [_blackWhiteSlider setEnabled:(validRange && validLevels)];
   [_gammaText setEnabled:(validRange && validLevels)];
   [_gammaSlider setEnabled:(validRange && validLevels)];

   if ( validRange )
   {
      [_blackWhiteSlider setMinValue:fmin(vmin,black)];
      [_blackWhiteSlider setMaxValue:fmax(vmax,white)];
      [_blackWhiteSlider setDoubleLoValue:black];
      [_blackWhiteSlider setDoubleHiValue:white];
      [_gammaSlider setDoubleValue:log(gamma)/MM_LN_10];
   }

   if ( validLevels )
   {
      [_blackText setDoubleValue:black];
      [_whiteText setDoubleValue:white];
      [_gammaText setDoubleValue:gamma];
   }
   else
   {
      [_blackText setStringValue:@""];
      [_whiteText setStringValue:@""];
      [_gammaText setStringValue:@""];
   }

   [self applyZoom:_zoom from:nil];
   [[self window] invalidateCursorRectsForView:self];
}

- (void) resetBounds
{
   NSRect r = {{0.0, 0.0}, {1.0, 1.0}};
   [self setFrameSize:r.size];
   [self setFrameOrigin:r.origin];
   [self setBoundsSize:r.size];
   [self setBoundsOrigin:r.origin];
}

// Drawing
- (void)drawRect:(NSRect)rect
{
   NSGraphicsContext *g = [NSGraphicsContext currentContext];

   if ( _imageRep != nil )
   {
      NSRect r = NSMakeRect(0.0, 0.0, _itemSize.width, _itemSize.height);
      [g saveGraphicsState];
      if ( _imageTransform != nil )
         [_imageTransform concat];
      [_imageRep drawInRect:r];
      [g restoreGraphicsState];
   }

   if ( _draggingMode != SelNone || [_selection count] != 0 )
   {
      [g saveGraphicsState];
      [[NSColor orangeColor] set];

      NSEnumerator *selectionList = [_selection objectEnumerator];
      MyImageSelection *sel = nil;
      SelectionIndex_t i = NSNotFound;

      do
      {
         LynkeosIntegerRect r;

         if ( sel == nil )
            r = _inProgressSelection;
         else
            r = sel->_rect;

         if ( r.size.width != 0 && r.size.height != 0 )
         {
            if ( i == _currentSelectionIndex
                 && (_inProgressSelection.size.width != 0
                     || _inProgressSelection.size.height != 0) )
               // Do not display the active selection during modification
               continue;
            if ( sel == nil || i == _currentSelectionIndex )
            {
               [g saveGraphicsState];
               [[NSColor redColor] set];
            }
            [NSBezierPath strokeRect:NSRectFromIntegerRect(r)];
            if ( sel == nil || i == _currentSelectionIndex )
               [g restoreGraphicsState];
         }
         i = (i == NSNotFound ? 0 : i+1);
      } while ( (sel = [selectionList nextObject]) != nil );

      [g restoreGraphicsState];
   }

   // Give an opportunity to add drawings
   [[NSNotificationCenter defaultCenter] postNotificationName: LynkeosImageViewRedrawNotification
                                                       object: self];
}

- (NSSize) imageSize { return( _canvasRect.size ); }

- (double) getZoom { return ( _zoom ); }

- (void) setZoom:(double)zoom
{
   [self applyZoom:zoom from:nil];
}

- (LynkeosIntegerRect) getSelection
{
   if ( _currentSelectionIndex < [_selection count])
      return( [self getSelectionAtIndex:_currentSelectionIndex] );
   else
      return( LynkeosMakeIntegerRect(0, 0, 0, 0) );
}

- (SelectionIndex_t) numberOfSelections
{ return( [_selection count] ); }

- (SelectionIndex_t) activeSelectionIndex
{ return( _currentSelectionIndex); }

- (LynkeosIntegerRect) getSelectionAtIndex:(SelectionIndex_t)index
{
   if ( [_selection count] > 0 )
   {
      MyImageSelection *sel = [_selection objectAtIndex:index];
      NSAssert( sel != nil, @"No selection in non nil selection list" );
      return( sel->_rect );
   }
   else
      return( LynkeosMakeIntegerRect(0, 0, 0, 0) );
}

- (unsigned int) getModifiers { return( _modifiers ); }

- (void) setSelectionMode:(SelectionMode_t)mode
{
   NSAssert( [_selection count] == 0,
             @"setSelectionMode called with active selections" );
   _selectionMode = mode;
}

- (void) freezeSelections:(BOOL)freeze
{
   if ( freeze )
   {
      if ( _freezeCounter == 0 )
      {
         _savedSelectionMode = _selectionMode;
         _selectionMode = NoSelection;
      }
      _freezeCounter++;
   }
   else
   {
      _freezeCounter--;
      if ( _freezeCounter == 0 )
      {
         _selectionMode = _savedSelectionMode;
         _savedSelectionMode = NoSelection;
      }
   }
}

- (void) setSelection :(LynkeosIntegerRect)selection
             resizable:(BOOL)resize
               movable:(BOOL)move
{
   SelectionIndex_t index;

   if ( _selectionMode == SingleSelection )
      index = 0;

   else if ( _currentSelectionIndex < [_selection count] )
      index = _currentSelectionIndex;

   else
      index = [_selection count];

   [self setSelection:selection atIndex:index resizable:resize movable:move];
}

- (void) setSelection :(LynkeosIntegerRect)selection
               atIndex:(SelectionIndex_t)index
             resizable:(BOOL)resize
               movable:(BOOL)move
{
   const SelectionIndex_t nSel = [_selection count];
   LynkeosIntegerRect selRect = selection;
   LynkeosIntegerRect oldRect = {{0,0},{0,0}};
   BOOL oldMovable = NO, oldResizable = NO;
   SelectionIndex_t oldIndex = index;

   if (_selectionMode == NoSelection)
   {
      NSLog(@"Trying to set a selection in NoSelection mode" );
      return;
   }
   NSAssert( index <= nSel,
             @"Trying to add a selection at an invalid index" );

   if ( index < nSel )
      [self getSelectionAtIndex:index
                           rect:&oldRect
                      resizable:&oldResizable movable:&oldMovable];

   // Correct the selection if needed
   if ( _selectionDelegate != nil )
   {
      if ( ![_selectionDelegate validateSelection:&selRect
                                          atIndex:index] )
      {
         selRect.origin.x = 0;
         selRect.origin.y = 0;
         selRect.size.width = 0;
         selRect.size.height = 0;
      }
   }

   // Do not allow selection to be outside the image, even partly
   if ( _canvasRect.size.width == 0 || _canvasRect.size.height == 0 )
   {
      selRect.origin.x = 0;
      selRect.origin.y = 0;
      selRect.size.width = 0;
      selRect.size.height = 0;
   }
   else
   {
      if ( selRect.origin.x < _canvasRect.origin.x )
         selRect.origin.x = _canvasRect.origin.x;
      else if ( selRect.origin.x + selRect.size.width
                 > _canvasRect.origin.x + _canvasRect.size.width )
         selRect.origin.x = _canvasRect.size.width - selRect.size.width - 1;
      if ( selRect.origin.y < _canvasRect.origin.y )
         selRect.origin.y = _canvasRect.origin.y;
      else if ( selRect.origin.y + selRect.size.height
                 > _canvasRect.origin.y + _canvasRect.size.height )
         selRect.origin.y = _canvasRect.size.height - selRect.size.height - 1;
   }

   // Check if something has changed
   if ( (index < nSel && index == _currentSelectionIndex
         && oldRect.origin.x == selection.origin.x
         && oldRect.origin.y == selection.origin.y
         && oldRect.size.width == selection.size.width
         && oldRect.size.height == selection.size.height
         && oldMovable == move && oldResizable == resize)
        || (nSel == 0 && (selection.size.width == 0
                          || selection.size.height == 0)) )
   {
      // Nothing to do
      return;
   }
   else if ( _isNotifying  )
   {
      NSLog(@"Attempt to modify the selection during a selection change notification");
      return;
   }

   // If the final selection size is zero, remove it
   if ( selRect.size.width == 0 || selRect.size.height == 0 )
   {
      if (index < [_selection count])
         [self removeSelectionAtIndex:index];
   }
   else
   {
      MyImageSelection *sel = [[[MyImageSelection alloc] initWithRect:selRect
                                                              movable:move
                                                            resizable:resize]
                                                                   autorelease];

      _modifiers = 0;

      if ( index < nSel )
      {
         if ( ![sel isEqual:[_selection objectAtIndex:index]] )
            [_selection replaceObjectAtIndex:index withObject:sel];
      }
      else
         [_selection addObject:sel];
      _currentSelectionIndex = index;


      [self setNeedsDisplay:YES];
      [[self window] invalidateCursorRectsForView:self];

      // If the selection was adjusted, notify it
      if (    index != oldIndex
           || selRect.origin.x    != oldRect.origin.x
           || selRect.origin.y    != oldRect.origin.y
           || selRect.size.width  != oldRect.size.width
           || selRect.size.height != oldRect.size.height )
      {
         _isNotifying = YES;
         [[NSNotificationCenter defaultCenter] postNotificationName:
                              LynkeosImageViewSelectionRectDidChangeNotification
                                                             object: self
                                                           userInfo:
          [NSDictionary dictionaryWithObjectsAndKeys:
              [NSNumber numberWithUnsignedInteger: _currentSelectionIndex],
              LynkeosImageViewSelectionRectIndex,
              nil]];
         _isNotifying = NO;
      }
   }
}

- (void) removeSelectionAtIndex:(SelectionIndex_t)index
{
   if (_selectionMode == NoSelection)
   {
      NSLog(@"Trying to remove a selection in NoSelection mode" );
      return;
   }
   NSAssert( index < [_selection count],
             @"Trying to remove a nonexistent selection" );

   [_selection removeObjectAtIndex:index];
   SelectionIndex_t newCount = [_selection count];
   if ( newCount != 0 && _currentSelectionIndex >= newCount )
      _currentSelectionIndex = newCount - 1;

   else if ( newCount == 0 )
      _currentSelectionIndex = NSNotFound;

   [self setNeedsDisplay:YES];
   [[self window] invalidateCursorRectsForView:self];

   _isNotifying = YES;
   [[NSNotificationCenter defaultCenter] postNotificationName:
                                 LynkeosImageViewSelectionWasDeletedNotification
                                                       object: self
                                                     userInfo:
                                 [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSValue valueWithRange:
                                                         NSMakeRange(index, 1)],
                                    LynkeosImageViewSelectionRange,
                                    nil]];
   _isNotifying = NO;
}

- (void) removeAllSelections
{
   const SelectionIndex_t nSel = [_selection count];

   if (nSel == 0)
      // Nothing to remove
      return;
   if (_selectionMode == NoSelection)
   {
      NSLog(@"Trying to remove selections in NoSelection mode" );
      return;
   }

   if ( nSel != 0 )
   {
      [_selection removeAllObjects];
      _currentSelectionIndex = NSNotFound;

      [self setNeedsDisplay:YES];
      [[self window] invalidateCursorRectsForView:self];

      _isNotifying = YES;
      [[NSNotificationCenter defaultCenter] postNotificationName:
                                 LynkeosImageViewSelectionWasDeletedNotification
                                                       object: self
                                                     userInfo:
                                 [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSValue valueWithRange:
                                                          NSMakeRange(1, nSel)],
                                  LynkeosImageViewSelectionRange,
                                  nil]];
      _isNotifying = NO;
   }
}


- (void) setSelectionDelegate:(id <LynkeosImageViewDelegate>)delegate
{
   _selectionDelegate = delegate;
}
@end
