source: trunk/PrefsPane/src/VerticalViewFlow.m @ 1046

Revision 789, 11.3 KB checked in by speck, 3 years ago (diff)

Compile Prefs Panel in 64 bit mode. Fix lots of 64->32 bit conversions because NSInteger becomes 64 bit while 'int' remains 32 bit.

Line 
1/* Copyright (C) 2008-2009 Peter Speck
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#import "VerticalViewFlow.h"
18#import "GBDebug.h"
19
20#ifdef DEBUG
21//#defined DEBUG_TABLEVIEW 1
22#endif
23
24@implementation VerticalViewFlowRow
25
26- (id)initWithFrame:(NSRect)frameRect
27{
28    if (!(self = [super initWithFrame:frameRect]))
29        return nil;
30    return self;
31}
32
33- (void)dealloc  // clang-sa wants a dealloc even though there's nothing to do.
34{
35    [super dealloc];
36}
37
38- (void)setRowNumber:(NSUInteger)rowNumber
39{
40    if (_rowNumber == rowNumber)
41        return;
42    _rowNumber = rowNumber;
43    [self setNeedsDisplay:YES];
44}
45
46- (NSUInteger)rowNumber
47{
48    return _rowNumber;
49}
50
51- (void)setSelected:(BOOL)selected
52{
53    if (_selected == selected)
54        return;
55    _selected = selected;
56    if (!selected)
57        [self endEditing];
58    [self setNeedsDisplay:YES];
59}
60
61- (BOOL)selected
62{
63    return _selected;
64}
65
66- (void)drawRect:(NSRect)r
67{
68    if (_selected) {
69        if ([self shouldDrawUsingFocusColor])
70            [[NSColor alternateSelectedControlColor] set];
71        else
72            [[NSColor secondarySelectedControlColor] set];
73    } else {
74        NSArray* a = [NSColor controlAlternatingRowBackgroundColors];
75        NSUInteger idx = _rowNumber % [a count];
76        [[a objectAtIndex:idx] set];
77    }
78    NSRectFill(r);
79}
80
81- (BOOL)shouldDrawUsingFocusColor
82{
83    if (!_selected)
84        return NO;
85    NSWindow* window = [self window];
86    if (![window isKeyWindow])
87        return NO;
88    return [self isEditing] || [[self tableView] isFirstResponder];
89}
90
91- (BOOL)isEditing
92{
93    return NO;
94}
95
96- (void)endEditing
97{
98}
99
100- (VerticalViewFlow*)tableView
101{
102    NSView* view = [self superview];
103    while (view) {
104        if ([view isKindOfClass:[VerticalViewFlow class]])
105            return (VerticalViewFlow*)view;
106        view = [view superview];
107    }
108    return NULL;
109}
110
111@end
112
113@interface VerticalViewFlow()
114
115- (void)removeNotifications;
116- (void)contentResized:(NSNotification*)notification;
117
118@end
119
120@implementation VerticalViewFlow
121
122- (BOOL) isFlipped
123{
124    return YES;
125}
126
127- (void)findScroller
128{
129    if (_scrollView)
130        return;
131    NSView* parent = self;;
132    while (1) {
133        parent = [parent superview];
134        if (!parent)
135            return;
136        if ([parent isKindOfClass:[NSClipView class]])
137            continue;
138        if ([parent isKindOfClass:[NSScrollView class]])
139            break;
140        return;
141    }
142    _scrollView = (NSScrollView*)parent;
143    NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
144    [nc addObserver:self
145           selector:@selector(contentResized:)
146               name:NSViewFrameDidChangeNotification
147             object:_scrollView];
148}
149
150- (id)initWithFrame:(NSRect)frameRect
151{
152    if (!(self = [super initWithFrame:frameRect]))
153        return nil;
154    _rows = [[NSMutableArray arrayWithCapacity:10] retain];
155    [self performSelectorOnMainThread:@selector(findScroller) withObject:NULL waitUntilDone:NO];
156    return self;
157}
158
159- (void)dealloc
160{
161    if (_scrollView) {
162        NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
163        [nc addObserver:self
164               selector:@selector(contentResized:)
165                   name:NSViewFrameDidChangeNotification
166                 object:_scrollView];
167    }
168    [self removeNotifications];
169    [_rows release];
170    [super dealloc];
171}
172
173- (void)setDelegate:(id<VerticalViewFlowDelegate>)delegate
174{
175    _delegate = delegate;
176}
177
178- (id<VerticalViewFlowDelegate>)delegate
179{
180    return _delegate;
181}
182
183- (void)contentResized:(NSNotification*)notification
184{
185    [self findScroller];
186    [self updateRowViewFrames];
187}
188
189- (void)removeNotifications
190{
191    if (!_notificationWindow)
192        return;
193    NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
194    [nc removeObserver:self
195                  name:NSWindowDidBecomeKeyNotification
196                object:_notificationWindow];
197    [nc removeObserver:self
198                  name:NSWindowDidResignKeyNotification
199                object:_notificationWindow];
200    [_notificationWindow release];
201    _notificationWindow = NULL;
202}
203
204- (void)handleWindowBecameResignedKey:(id)sender
205{
206    [self repaintSelectedRows];
207}
208
209- (void)viewDidMoveToWindow
210{
211    [self removeNotifications];
212    _notificationWindow = [[self window] retain];
213    if (!_notificationWindow)
214        return;
215    NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
216    [nc addObserver:self
217           selector:@selector(handleWindowBecameResignedKey:)
218               name:NSWindowDidBecomeKeyNotification
219             object:_notificationWindow];
220    [nc addObserver:self
221           selector:@selector(handleWindowBecameResignedKey:)
222               name:NSWindowDidResignKeyNotification
223             object:_notificationWindow];
224}
225
226- (void)addRow:(VerticalViewFlowRow*)view atIndex:(NSUInteger)idx
227{
228    if (idx >= [_rows count])
229        [_rows addObject:view];
230    else
231        [_rows insertObject:view atIndex:idx];
232    [self addSubview:view];
233    if ([_delegate respondsToSelector:@selector(vertPatchTableAddedRow:)])
234        [_delegate vertPatchTableAddedRow:self];
235    [self updateRowViewFrames];
236}
237
238- (void)removeRow:(VerticalViewFlowRow*)view
239{
240    [_rows removeObject:view];
241    if ([view superview] == self)
242        [view removeFromSuperview];
243    if ([_delegate respondsToSelector:@selector(vertPatchTableRemovedRow:)])
244        [_delegate vertPatchTableRemovedRow:self];
245    [self updateRowViewFrames];
246}
247
248- (id)rowByIndex:(NSUInteger)idx
249{
250    return [_rows objectAtIndex:idx];
251}
252
253- (NSUInteger)rowCount
254{
255    return [_rows count];
256}
257
258- (NSArray*)rows
259{
260    return [NSArray arrayWithArray:_rows];
261}
262
263- (void)setFreezeUpdates:(BOOL)freeze
264{
265    if (freeze == _freezeUpdates)
266        return;
267    _freezeUpdates = freeze;
268    if (!freeze)
269        [self updateRowViewFrames];
270}
271
272- (void)updateRowViewFrames
273{
274    if (_freezeUpdates)
275        return;
276    NSUInteger num = [_rows count];
277    CGFloat totalHeight = 0;
278    CGFloat maxWidth = 0;
279    for (NSUInteger i = 0; i < num; i++) {
280        VerticalViewFlowRow* view = [_rows objectAtIndex:i];
281        NSRect r = [view frame];
282        totalHeight += r.size.height;
283        maxWidth = MAX(maxWidth, r.size.width);
284    }
285    NSRect parentFrame = [[self superview] frame];
286    totalHeight = MAX(totalHeight, parentFrame.size.height);
287    NSRect sr = [self frame];
288    if (sr.size.width != maxWidth || sr.size.height != totalHeight)
289        [self setFrameSize:NSMakeSize(maxWidth, totalHeight)];
290#ifdef DEBUG_TABLEVIEW
291    DebugNSLog(@"updateRowViewFrames, maxW = %f, totalHeight = %f", maxWidth, totalHeight);
292#endif
293    CGFloat y = 0;
294    for (NSUInteger i = 0; i < num; i++) {
295        VerticalViewFlowRow* view = [_rows objectAtIndex:i];
296        NSRect vr = [view frame];
297#ifdef DEBUG_TABLEVIEW
298        DebugNSLog(@"   origin[%d]:  0, %f   height=%f", i, y, vr.size.height);
299#endif
300        if (vr.origin.y != y) {
301            [view setFrameOrigin:NSMakePoint(0, y)];
302            [view setNeedsDisplay:YES];
303        }
304        [view setRowNumber:i];
305        _lastRowHeight = vr.size.height;
306        y += vr.size.height;
307    }
308    _rowBottomY = y;
309}
310
311- (void)drawDummyRows
312{
313    NSArray* a = [NSColor controlAlternatingRowBackgroundColors];
314    NSRect r = [self frame];
315    CGFloat endY = r.size.height;
316    r.origin.y = _rowBottomY;
317    r.size.height = _lastRowHeight;
318    for (NSUInteger row = [_rows count]; r.origin.y < endY; row++) {
319        NSUInteger idx = row % [a count];
320        [[a objectAtIndex:idx] set];
321        NSRectFill(r);
322        r.origin.y += r.size.height;
323    }
324}
325
326- (void)repaintSelectedRows
327{
328#ifdef DEBUG_TABLEVIEW
329    NSLog(@"repaintSelectedRows");
330#endif
331    NSUInteger num = [_rows count];
332    for (NSUInteger i = 0; i < num; i++) {
333        VerticalViewFlowRow* view = [_rows objectAtIndex:i];
334        if ([view selected])
335            [view setNeedsDisplay:YES];
336    }
337}
338
339- (void)drawRect:(NSRect)theRect
340{
341    if (_lastRowHeight && _rowBottomY >= theRect.origin.y)
342        [self drawDummyRows];
343}
344
345- (void)setSelectionByView:(VerticalViewFlowRow*)selectedView
346{
347    NSUInteger num = [_rows count];
348    BOOL changed = NO;
349    for (NSUInteger i = 0; i < num; i++) {
350        VerticalViewFlowRow* view = [_rows objectAtIndex:i];
351        BOOL wanted = (view == selectedView);
352        if ([view selected] == wanted)
353            continue;
354        [view setSelected:wanted];
355        changed = YES;
356    }
357    if (!changed)
358        return;
359    if ([_delegate respondsToSelector:@selector(vertPatchTableChangedSelection:)])
360        [_delegate vertPatchTableChangedSelection:self];
361}
362
363- (void)setSelectionByIndex:(NSUInteger)idx
364{
365    [self setSelectionByView:[self rowByIndex:idx]];
366}
367
368- (id)firstSelectedRow
369{
370    NSUInteger num = [_rows count];
371    for (NSUInteger i = 0; i < num; i++) {
372        VerticalViewFlowRow* view = [_rows objectAtIndex:i];
373        if ([view selected])
374            return view;
375    }
376    return NULL;
377}
378
379- (id)lastSelectedRow
380{
381    NSUInteger num = [_rows count];
382    if (num == 0)
383        return NULL;
384    for (NSUInteger i = num - 1; 1; i--) {
385        VerticalViewFlowRow* view = [_rows objectAtIndex:i];
386        if (i == 0 || [view selected])
387            return view;
388    }
389}
390
391- (BOOL)acceptsFirstResponder
392{
393    return YES;
394}
395
396- (void)keyDown:(NSEvent*)theEvent
397{
398    NSUInteger mask = NSAlphaShiftKeyMask | NSShiftKeyMask | NSControlKeyMask
399        | NSAlternateKeyMask | NSCommandKeyMask;
400    if ([theEvent modifierFlags] & mask) {
401        [super keyDown:theEvent];
402        return;
403    }
404    NSString* s = [theEvent characters];
405    for (NSUInteger si = 0; si < [s length]; si++) {
406        unichar ch = [s characterAtIndex:si];
407        if (ch == NSUpArrowFunctionKey) {
408            VerticalViewFlowRow* row = [self firstSelectedRow];
409            if (row && [row rowNumber] > 0)
410                [self setSelectionByIndex:[row rowNumber] - 1];
411            else if (!row && [_rows count])
412                [self setSelectionByIndex:[_rows count] - 1];
413        }
414        if (ch == NSDownArrowFunctionKey) {
415            VerticalViewFlowRow* row = [self lastSelectedRow];
416            if (row && [row rowNumber] < [_rows count] - 1)
417                [self setSelectionByIndex:[row rowNumber] + 1];
418            else if (!row && [_rows count])
419                [self setSelectionByIndex:0];
420        }
421    }
422    [super keyDown:theEvent];
423}
424
425- (void)updateDrawFocusRing:(BOOL)flag
426{
427    NSView* view = [self superview];
428    while (view) {
429        if ([view isKindOfClass:[ScrollViewWithFocusRing class]]) {
430            ScrollViewWithFocusRing* scroller = (ScrollViewWithFocusRing*)view;
431            [scroller setDrawFocusRing:flag];
432            return;
433        }
434        view = [view superview];
435    }
436}
437
438- (void)mouseDown:(NSEvent *)theEvent
439{
440#ifdef DEBUG_TABLEVIEW
441    DebugNSLog(@"MouseDown in table view: %@", theEvent);
442#endif
443    NSUInteger num = [_rows count];
444    for (NSUInteger i = 0; i < num; i++) {
445        VerticalViewFlowRow* view = [_rows objectAtIndex:i];
446        [view endEditing];
447    }
448}
449
450- (BOOL)becomeFirstResponder
451{
452    _isFirstResponder = YES;
453#ifdef DEBUG_TABLEVIEW
454    NSWindow* window = [self window];
455    DebugNSLog(@"TableView.becomeFirstResponder: main = %d, isRF = %d",
456          [window isMainWindow], [window firstResponder] == self);
457#endif
458    [self repaintSelectedRows];
459    [self updateDrawFocusRing:YES];
460    return YES;
461}
462
463- (BOOL)resignFirstResponder
464{
465#ifdef DEBUG_TABLEVIEW
466    DebugNSLog(@"TableView.resignFirstResponder");
467#endif
468    _isFirstResponder = NO;
469    [self repaintSelectedRows];
470    [self updateDrawFocusRing:NO];
471    return YES;
472}
473
474- (BOOL)isFirstResponder
475{
476    return _isFirstResponder;
477}
478
479@end
480
481@implementation ScrollViewWithFocusRing
482
483- (id)initWithFrame:(NSRect)frameRect
484{
485    if (!(self = [super initWithFrame:frameRect]))
486        return nil;
487    return self;
488}
489
490- (void)dealloc
491{
492    [super dealloc];
493}
494
495- (void)setDrawFocusRing:(BOOL)flag
496{
497    if (flag == _drawFocusRing)
498        return;
499    _drawFocusRing = flag;
500    [self setKeyboardFocusRingNeedsDisplayInRect: [self bounds]];
501}
502
503- (void)drawRect:(NSRect)r
504{
505    [super drawRect:r];
506    if (!_drawFocusRing)
507        return;
508    NSSetFocusRingStyle(NSFocusRingOnly);
509    NSRectFill([self bounds]);
510}
511
512@end
Note: See TracBrowser for help on using the repository browser.