/*
HMImageTextFieldCell.m

Author: Makoto Kinoshita

Copyright 2004-2006 The Shiira Project. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of 
  conditions and the following disclaimer in the documentation and/or other materials provided 
  with the distribution.

THIS SOFTWARE IS PROVIDED BY THE SHIIRA PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SHIIRA PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/

#import "HMAppKitEx.h"
#import "HMImageTextFieldCell.h"

static int  HMMarginImage = 4;
static int  HMMarginBetweenImageAndText = 4;

@implementation HMImageTextFieldCell

//--------------------------------------------------------------//
#pragma mark -- Initialize --
//--------------------------------------------------------------//

- (id)init
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
    // Initialize instance variables
    _padding = HMMarginBetweenImageAndText;
    _focusRingIncludesImage = NO;
    _useBoldForHighlight = NO;
    
    // Configure itself
    [self setWraps:NO];
    
    return self;
}

- (void)dealloc
{
    [_image release], _image = nil;
    
    [super dealloc];
}

- (id)copyWithZone:(NSZone*)zone
{
    HMImageTextFieldCell*   cell;
    cell = (HMImageTextFieldCell*)[super copyWithZone:zone];
    cell->_image = [_image retain];
    
    return cell;
}

//--------------------------------------------------------------//
#pragma mark -- Image management --
//--------------------------------------------------------------//

- (void)setImage:(NSImage*)image {
    if (_image != image) {
        [_image release];
        _image = [image retain];
    }
}

- (NSImage *)image {
    return _image;
}

- (int)paddingBetweenImageAndText
{
    return _padding;
}

- (void)setPaddingBetweenImageAndText:(int)padding
{
    _padding = padding;
}

- (BOOL)focusRingIncludesImage
{
    return _focusRingIncludesImage;
}

- (void)setFocusRingIncludesImage:(BOOL)flag
{
    _focusRingIncludesImage = flag;
}

//--------------------------------------------------------------//
#pragma mark -- Separator --
//--------------------------------------------------------------//

- (BOOL)isSeparator
{
    return _isSeparator;
}

- (void)setSeparator:(BOOL)isSepartor
{
    _isSeparator = isSepartor;
}

//--------------------------------------------------------------//
#pragma mark -- Highlight --
//--------------------------------------------------------------//

- (BOOL)useBoldForHighlight
{
    return _useBoldForHighlight;
}

- (void)setUseBoldForHighlight:(BOOL)flag
{
    _useBoldForHighlight = flag;
}

//--------------------------------------------------------------//
#pragma mark -- Text attribute --
//--------------------------------------------------------------//

- (NSDictionary*)_textAttributes
{
    // Check flag
    if (!_useBoldForHighlight) {
        return [super _textAttributes];
    }
    
    // Copy attributes
    NSMutableDictionary*    attrs;
    attrs = [NSMutableDictionary dictionaryWithDictionary:[super _textAttributes]];
    
    // Add paragraph style
    static NSMutableParagraphStyle* _paragraph = nil;
    if (!_paragraph) {
        _paragraph = [[NSMutableParagraphStyle alloc] init];
        [_paragraph setLineBreakMode:NSLineBreakByTruncatingTail];
    }
    [attrs setObject:_paragraph forKey:NSParagraphStyleAttributeName];
    
    // For highlight
    NSView*     controlView;
    NSWindow*   window;
    controlView = [self controlView];
    window = [controlView window];
    if ([self isHighlighted] && 
        [window isKeyWindow] && 
        [window firstResponder] == controlView)
    {
        // Make font bold
        NSFont* font;
        font = [attrs objectForKey:NSFontAttributeName];
        font = [[NSFontManager sharedFontManager] 
                convertFont:font toHaveTrait:NSBoldFontMask];
        [attrs setObject:font forKey:NSFontAttributeName];
        
        // Add shadow
        static NSShadow*    _shadow = nil;
        if (!_shadow) {
            _shadow = [[NSShadow alloc] init];
            [_shadow setShadowOffset:NSMakeSize(0, -1)];
            [_shadow setShadowColor:[NSColor blackColor]];
        }
        [attrs setObject:_shadow forKey:NSShadowAttributeName];
    }
    
    return attrs;
}

//--------------------------------------------------------------//
#pragma mark -- Dragging and dropping --
//--------------------------------------------------------------//

- (BOOL)shouldImageTrackMouse:(NSEvent*)event 
        inRect:(NSRect)cellFrame 
        ofView:(NSView*)controlView 
{
    // Check mouse is in image or not
    NSRect  textFrame, imageFrame;
    NSPoint point;
    NSDivideRect(cellFrame, &imageFrame, &textFrame, _padding + [_image size].width, NSMinXEdge);
    point = [controlView convertPoint:[event locationInWindow] fromView:nil];
    
    return NSPointInRect(point, imageFrame);
}

- (BOOL)imageTrackMouse:(NSEvent*)event 
        inRect:(NSRect)cellFrame 
        ofView:(NSView*)controlView 
{
    // Check mouse is in image or not
    NSRect  textFrame, imageFrame;
    NSPoint point;
    NSDivideRect(cellFrame, &imageFrame, &textFrame, _padding + [_image size].width, NSMinXEdge);
    point = [controlView convertPoint:[event locationInWindow] fromView:nil];
    if (!NSPointInRect(point, imageFrame)) {
        return NO;
    }
    
    //
    // Start dragging
    //
    
    id  dragDelegate = nil;
    if ([controlView respondsToSelector:@selector(dragDelegate)]) {
        dragDelegate = [controlView performSelector:@selector(dragDelegate)];
    }
    
    // Create drag image
    NSImage*    dragImage = nil;
    if (dragDelegate && [dragDelegate 
            respondsToSelector:@selector(imageTextCell:dragImageForEvent:inRect:ofView:dragImageOffset:)])
    {
        // Invoke delegate
        NSPoint dragImageOffset;
        dragImage = [dragDelegate imageTextCell:self 
                dragImageForEvent:event 
                inRect:cellFrame 
                ofView:controlView 
                dragImageOffset:&dragImageOffset];
    }
    else {
    }
    
    // Write data to pasteboard
    NSPasteboard*   pboard;
    pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    if (dragDelegate && [dragDelegate 
            respondsToSelector:@selector(imageTextCell:writeToPasteboard:)])
    {
        // Invoke delegate
        if (![dragDelegate imageTextCell:self writeToPasteboard:pboard]) {
            return NO;
        }
    }
    else {
    }
    
    // Start dragging
    NSPoint startAt;
    startAt = imageFrame.origin;
    if ([controlView isFlipped]) {
        startAt.y = cellFrame.size.height - startAt.y;
    }
    
    [controlView dragImage:dragImage 
            at:startAt 
            offset:NSZeroSize 
            event:event 
            pasteboard:pboard 
            source:self 
            slideBack:YES];
    
    return YES;
}

- (void)resetCursorRect:(NSRect)cellFrame 
        inView:(NSView*)controlView
{
    NSRect  textFrame, imageFrame;
    NSDivideRect(cellFrame, &imageFrame, &textFrame, _padding + [_image size].width, NSMinXEdge);
    
    [super resetCursorRect:textFrame inView:controlView];
}

//--------------------------------------------------------------//
#pragma mark -- Drawing --
//--------------------------------------------------------------//

- (void)editWithFrame:(NSRect)rect 
        inView:(NSView*)controlView 
        editor:(NSText*)textObj 
        delegate:(id)delegate 
        event:(NSEvent*)event
{
    NSRect  textFrame, imageFrame;
    NSDivideRect(rect, &imageFrame, &textFrame, _padding + [_image size].width, NSMinXEdge);
    [super editWithFrame:textFrame 
            inView:controlView 
            editor:textObj 
            delegate:delegate 
            event:event];
}

- (void)selectWithFrame:(NSRect)rect 
        inView:(NSView*)controlView 
        editor:(NSText*)textObj 
        delegate:(id)delegate 
        start:(int)selStart 
        length:(int)selLength
{
    NSRect  textFrame, imageFrame;
    NSDivideRect(
            rect, 
            &imageFrame, 
            &textFrame, 
            HMMarginImage + _padding + [_image size].width, 
            NSMinXEdge);
    [super selectWithFrame:textFrame 
            inView:controlView 
            editor:textObj 
            delegate:delegate 
            start:selStart 
            length:selLength];
}

- (void)_drawSeparatorWithFrame:(NSRect)cellFrame 
        inView:(NSView*)controlView
{
    // Draw separator
    NSRect  rect;
    
#if 1
    [[NSColor colorWithCalibratedWhite:0.36f alpha:1.0f] set];
    rect.origin.x = cellFrame.origin.x;
    rect.origin.y = cellFrame.origin.y + ceil(cellFrame.size.height / 2) - 1;
    rect.size.width = cellFrame.size.width;
    rect.size.height = 1;
    NSRectFill(rect);
#else
    [[NSColor colorWithCalibratedWhite:0.6f alpha:0.8f] set];
    rect.origin.x = cellFrame.origin.x;
    rect.origin.y = cellFrame.origin.y + ceil(cellFrame.size.height / 2) - 1;
    rect.size.width = cellFrame.size.width;
    rect.size.height = 1;
    NSRectFill(rect);
    
    [[NSColor colorWithCalibratedWhite:0.9f alpha:0.8f] set];
    rect.origin.y += 1;
    NSRectFill(rect);
#endif
}

- (void)drawInteriorWithFrame:(NSRect)cellFrame 
        inView:(NSView*)controlView
{
    // For separator
    if (_isSeparator) {
        [self _drawSeparatorWithFrame:cellFrame inView:controlView];
        return;
    }
    
    // Calc image and text frame
    NSRect  imageFrame;
    NSRect  textFrame;
    if (_image) {
        NSDivideRect(
                cellFrame, &imageFrame, &textFrame, 
                HMMarginImage + _padding + [_image size].width, NSMinXEdge);
    }
    else {
        imageFrame = NSZeroRect;
        textFrame = cellFrame;
    }
    
    // Draw image
    if (_image) {
        // Decide image frame
        NSSize	size;
        NSRect	frame;
        size = [_image size];
        frame.origin = imageFrame.origin;
        frame.origin.x += HMMarginImage;
        frame.size = size;
        if ([controlView isFlipped]) {
            frame.origin.y += floor((cellFrame.size.height + frame.size.height) / 2);
        }
        else {
            frame.origin.y += floor((cellFrame.size.height - frame.size.height) / 2);
        }
        
        // Draw image
        [_image compositeToPoint:frame.origin operation:NSCompositeSourceOver];
    }
    
    // Check string height
    NSAttributedString* attrString;
    attrString = [self attributedStringValue];
    if (attrString) {
        NSSize  stringSize;
        stringSize = [attrString size];
        if (stringSize.height > 0 && textFrame.size.height > stringSize.height) {
            int y;
            y = ceil((textFrame.size.height - stringSize.height) / 2);
            textFrame.origin.y += y;
            textFrame.size.height -= y;
        }
    }
    
    // Draw text
    [super drawInteriorWithFrame:textFrame inView:controlView];
}

@end
