1/*
2   Project: Cartotheque
3
4   Copyright (C) 2005 Stefan Urbanek
5
6   Author : Stefan Urbanek
7   Created: 2005-Feb
8   License: GNU LGPL 2.1
9*/
10
11#import "CardMatrix.h"
12
13#import "Card.h"
14#import "Cartotheque.h"
15
16#import <Foundation/NSNotification.h>
17#import <AppKit/NSColor.h>
18#import <AppKit/NSGraphics.h>
19#import <AppKit/NSBezierPath.h>
20#import <AppKit/NSCell.h>
21#import <AppKit/NSMatrix.h>
22#import <AppKit/NSScrollView.h>
23#import <AppKit/NSStringDrawing.h>
24#import <AppKit/PSOperators.h>
25
26@interface CardCell:NSCell
27@end
28
29@implementation CardCell
30- initWithCard:(Card *)card
31{
32    self = [super init];
33
34    [self setRepresentedObject:card];
35
36    return self;
37}
38- (void)drawInteriorWithFrame:(NSRect)cellFrame
39                       inView:(NSView *)controlView
40{
41    NSRect        rect;
42    NSRect        textRect;
43
44#define FACTOR 0.75 /* or whatever */
45    PSgsave();
46    PStranslate(cellFrame.origin.x,cellFrame.origin.y);
47    PSscale(FACTOR,FACTOR);
48    rect = NSMakeRect(0,0,cellFrame.size.width/FACTOR,
49                          cellFrame.size.height/FACTOR);
50
51    rect = NSInsetRect(rect, 4,4);
52
53    [[NSColor whiteColor] set];
54    [NSBezierPath fillRect:rect];
55    [[NSColor blackColor] set];
56    [NSBezierPath strokeRect:rect];
57
58    textRect = NSInsetRect(rect, 4,4);
59
60    /* FIXME: this works only for NSString/NSAttributeString card contents */
61    [[[self representedObject] contents] drawInRect: textRect];
62
63    PSgrestore();
64
65    if([self isHighlighted])
66    {
67        NSColor *color;
68        color = [NSColor selectedControlColor];
69        color = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
70        color = [color colorWithAlphaComponent:0.5];
71
72        [color set];
73        [NSBezierPath fillRect:cellFrame];
74    }
75}
76@end
77
78@interface CardMatrix(Private)
79- (void)_initSubviews;
80@end
81
82@implementation CardMatrix
83- initWithFrame:(NSRect)rect
84{
85    self = [super initWithFrame:rect];
86
87    [self _initSubviews];
88
89    return self;
90}
91- (void)awakeFromNib
92{
93    [self _initSubviews];
94}
95- (void)_initSubviews
96{
97    scrollView = [[NSScrollView alloc] initWithFrame:[self bounds]];
98    matrix = [[NSMatrix alloc] initWithFrame:NSMakeRect(0,0,0,0)];
99
100    [matrix setTarget:self];
101    [matrix setAction:@selector(cardSelectionChanged:)];
102    [matrix setDoubleAction:@selector(cardDoubleclicked:)];
103    [matrix setMode:NSListModeMatrix];
104    [matrix setAllowsEmptySelection:YES];
105
106    [scrollView setBorderType:NSBezelBorder];
107    [scrollView setDocumentView:matrix];
108    [scrollView setAutoresizingMask:[self autoresizingMask]];
109    [scrollView setHasVerticalScroller:YES];
110    [scrollView setHasHorizontalScroller:NO];
111
112    [self addSubview:scrollView];
113    cardFrameSize = NSMakeSize(80.0, 60.0);
114    cardSpacing = NSMakeSize(4.0, 4.0);
115
116    [self setPostsFrameChangedNotifications:YES];
117}
118- (void)dealloc
119{
120    /* FIXME: release subviews */
121    [[NSNotificationCenter defaultCenter] removeObserver:self];
122
123    RELEASE(cartotheque);
124    RELEASE(delegate);
125    [super dealloc];
126}
127- (void)setDelegate:(id)anObject
128{
129    ASSIGN(delegate, anObject);
130}
131- (void)setCartotheque:(Cartotheque *)cards
132{
133    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
134
135    ASSIGN(cartotheque, cards);
136
137    [nc removeObserver:self];
138
139    [nc addObserver:self
140           selector:@selector(cartothequeCardsChanged:)
141               name:CardCreatedNotification
142             object:cartotheque];
143
144    [nc addObserver:self
145           selector:@selector(frameDidChange:)
146               name:NSViewFrameDidChangeNotification
147             object:self];
148
149    /* FIXME: use some other, probably private, method */
150    [self reloadCards];
151}
152- (void)cardSelectionChanged:(id)sender
153{
154    Card *card;
155
156    card = [[matrix selectedCell] representedObject];
157
158    /* FIXME: add array of selected objetcs */
159    //[delegate cardMatrix:self didChangeSelection:nil];
160}
161- (void)cardDoubleclicked:(id)sender
162{
163    Card *card;
164
165    card = [[matrix selectedCell] representedObject];
166
167    if([delegate respondsToSelector:@selector(cardMatrix:openCard:)])
168    {
169        [delegate cardMatrix:self openCard:card];
170    }
171}
172- (void)reloadCards
173{
174    NSMutableArray *cells;
175    NSEnumerator   *enumerator;
176    CardCell       *cell;
177    NSSize          size;
178    Card           *card;
179    int             i;
180    int             columns;
181
182    /* remove all matrix cells */
183    while([matrix numberOfRows] > 0)
184    {
185        [matrix removeRow:0];
186    }
187    size = [scrollView contentSize];
188    columns = size.width / (cardFrameSize.width + cardSpacing.width);
189
190    enumerator = [[cartotheque allCards] objectEnumerator];
191
192    cells = [NSMutableArray array];
193
194    i = 0;
195
196    while( (card = [enumerator nextObject]) )
197    {
198        cell = [[CardCell alloc] initWithCard:card];
199        [cells addObject:AUTORELEASE(cell)];
200
201        i = i + 1;
202        if(i >= columns)
203        {
204            [matrix addRowWithCells:cells];
205            [cells removeAllObjects];
206            i = 0;
207        }
208    }
209    if([cells count] > 0)
210    {
211        [matrix addRowWithCells:cells];
212    }
213    [matrix setCellSize:cardFrameSize];
214    // [matrix setIntercellSpacing:cardSpacing];
215    [matrix sizeToCells];
216
217    /* FIXME: is this really needed? */
218    [matrix setNeedsDisplay:YES];
219    [scrollView setNeedsDisplay:YES];
220
221    [self setNeedsDisplay:YES];
222}
223- (NSArray *)selectedCards
224{
225    NSMutableArray *array;
226    NSEnumerator   *enumerator;
227    CardCell       *cell;
228    Card           *card;
229
230    array = [NSMutableArray array];
231    enumerator = [[matrix selectedCells] objectEnumerator];
232
233    while( (cell = [enumerator nextObject]) )
234    {
235        card = [cell representedObject];
236        [array addObject:card];
237    }
238
239    return [NSArray arrayWithArray:array];
240}
241
242- (void)setCardFrameSize:(NSSize)size
243{
244    cardFrameSize = size;
245}
246- (void)cartothequeCardsChanged:(NSNotification *)notification
247{
248    [self reloadCards];
249    [self setNeedsDisplay:YES];
250}
251- (void)frameDidChange:(NSNotification *)notification
252{
253    [self reloadCards];
254    [self setNeedsDisplay:YES];
255}
256@end
257