diff --git a/ChangeLog b/ChangeLog index c7e84fc4f..ffd21ef4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,141 @@ +Mon Apr 21 18:57:30 1997 Ovidiu Predescu + + * Implement NSCopying protocol to cell classes. + * Headers/gnustep/gui/NSCell.h: Declare class to conform to + NSCopying. + * Headers/gnustep/gui/NSActionCell.h: Likewise. + * Headers/gnustep/gui/NSButtonCell.h: Likewise. + * Source/NSCell.m: Implement copyWithZone:. + * Source/NSActionCell.m: Likewise. + * Source/NSButtonCell.m: Likewise. + + * Use NSRunLoop to get the events. + * Headers/gnustep/gui/NSApplication.h: Define USE_RUN_LOOP macro if you + want NSRunLoop class to be used instead of the default busy wait. Note + that some classes will not work with the "default" loop. This macro + should be removed eventually. + (-setupRunLoopInputSourcesForMode:): New method to be implemented in + backend. In this method the backend should register to run loop the + input sources it uses. + * Source/NSApplication.m (-init): Call backend method + -setupRunLoopInputSourcesForMode: to setup the input source is several + modes used by NSApp. + (-run): Get the events from NSDefaultRunLoopMode mode instead of nil. + (-nextEventMatchingMask:untilDate:inMode:dequeue:): Check for a + matching event into the events queue in the order in which the events + occured. Temporary retain the event found before removing it from the + events queue to avoid an unneeded deallocation. + Inside the loop fire the timers then wait for inputs on the input + sources of run loop. + * Source/NSButton.m: Call the nextEventMatchingMask:... using the + NSEventTrackingRunLoopMode mode instead of nil. + * Source/NSCell.m: (-trackMouse:inRect:ofView:untilMouseUp:): Likewise. + (-trackScrollButtons:): Likewise. + * Source/NSScroller.m (-trackKnob:): Likewise. + * Source/NSWindow.m (-nextEventMatchingMask:): Likewise. + + * NSMatrix class completely reworked to be compliant to the OpenStep + specification. + * Source/NSMatrix.m: The second implementation. + * Headers/gnustep/gui/NSMatrix.h: Likewise. + + * Implementation of NSForm, not tested. + * Source/NSForm.m: Initial implementation. + * Headers/gnustep/gui/NSForm.h: Likewise. + * Source/NSFormCell.m: Initial implementation. + * Headers/gnustep/gui/NSFormCell.h: Likewise. + + * Added support in configure and makefiles for libFoundation. + * configure.in: Configure checks now for the underlaying Foundation + library and the Objective-C runtime for whom the library was compiled + for. The code is copied with copy/paste from libFoundation sources. + * aclocal.m4: Likewise. + * Source/Makefile.in: New OBJC_RUNTIME_FLAG that gets replaced by + configure. Remove OBJC_LIB since the runtime library is added to LIBS + by configure. + + * Source/NSButton.m: Comment out captureMouse: method call to make + possible debugging. Anyway it seems we don't need to capture the mouse. + * Source/NSButtonCell.m: Remove the -prefersTrackingUntilMouseUp + method. + + * Source/NSCell.m: Changed the way in which a cell gets initialized. + Moved all the common things into the -_init method. + + * Added support for periodic events. + * Source/NSEvent.m: (+startPeriodicEventsAfterDelay:withPeriod:, + +stopPeriodicEvents): New public methods. + (+_timerFired:, +_registerRealTimer:): New private methods. + +Mon Apr 21 18:57:30 1997 Ovidiu Predescu + + * Implement NSCopying protocol to cell classes. + * Headers/gnustep/gui/NSCell.h: Declare class to conform to + NSCopying. + * Headers/gnustep/gui/NSActionCell.h: Likewise. + * Headers/gnustep/gui/NSButtonCell.h: Likewise. + * Source/NSCell.m: Implement copyWithZone:. + * Source/NSActionCell.m: Likewise. + * Source/NSButtonCell.m: Likewise. + + * Use NSRunLoop to get the events. + * Headers/gnustep/gui/NSApplication.h: Define USE_RUN_LOOP macro if you + want NSRunLoop class to be used instead of the default busy wait. Note + that some classes will not work with the "default" loop. This macro + should be removed eventually. + (-setupRunLoopInputSourcesForMode:): New method to be implemented in + backend. In this method the backend should register to run loop the + input sources it uses. + * Source/NSApplication.m (-init): Call backend method + -setupRunLoopInputSourcesForMode: to setup the input source is several + modes used by NSApp. + (-run): Get the events from NSDefaultRunLoopMode mode instead of nil. + (-nextEventMatchingMask:untilDate:inMode:dequeue:): Check for a + matching event into the events queue in the order in which the events + occured. Temporary retain the event found before removing it from the + events queue to avoid an unneeded deallocation. + Inside the loop fire the timers then wait for inputs on the input + sources of run loop. + * Source/NSButton.m: Call the nextEventMatchingMask:... using the + NSEventTrackingRunLoopMode mode instead of nil. + * Source/NSCell.m: (-trackMouse:inRect:ofView:untilMouseUp:): Likewise. + (-trackScrollButtons:): Likewise. + * Source/NSScroller.m (-trackKnob:): Likewise. + * Source/NSWindow.m (-nextEventMatchingMask:): Likewise. + + * NSMatrix class completely reworked to be compliant to the OpenStep + specification. + * Source/NSMatrix.m: The second implementation. + * Headers/gnustep/gui/NSMatrix.h: Likewise. + + * Implementation of NSForm, not tested. + * Source/NSForm.m: Initial implementation. + * Headers/gnustep/gui/NSForm.h: Likewise. + * Source/NSFormCell.m: Initial implementation. + * Headers/gnustep/gui/NSFormCell.h: Likewise. + + * Added support in configure and makefiles for libFoundation. + * configure.in: Configure checks now for the underlaying Foundation + library and the Objective-C runtime for whom the library was compiled + for. The code is copied with copy/paste from libFoundation sources. + * aclocal.m4: Likewise. + * Source/Makefile.in: New OBJC_RUNTIME_FLAG that gets replaced by + configure. Remove OBJC_LIB since the runtime library is added to LIBS + by configure. + + * Source/NSButton.m: Comment out captureMouse: method call to make + possible debugging. Anyway it seems we don't need to capture the mouse. + * Source/NSButtonCell.m: Remove the -prefersTrackingUntilMouseUp + method. + + * Source/NSCell.m: Changed the way in which a cell gets initialized. + Moved all the common things into the -_init method. + + * Added support for periodic events. + * Source/NSEvent.m: (+startPeriodicEventsAfterDelay:withPeriod:, + +stopPeriodicEvents): New public methods. + (+_timerFired:, +_registerRealTimer:): New private methods. + Fri Apr 04 14:03:40 1997 Scott Christley * Source/NSSlider.m (MB_NSSLIDER_CLASS): Rename to follow GNU diff --git a/Headers/gnustep/gui/AppKitExceptions.h b/Headers/gnustep/gui/AppKitExceptions.h index a16c7fcea..81c90b71c 100644 --- a/Headers/gnustep/gui/AppKitExceptions.h +++ b/Headers/gnustep/gui/AppKitExceptions.h @@ -3,7 +3,7 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Ovidiu Predescu + Author: Ovidiu Predescu Date: February 1997 This file is part of the GNUstep GUI Library. diff --git a/Headers/gnustep/gui/NSActionCell.h b/Headers/gnustep/gui/NSActionCell.h index 568b805f1..f9fe03fad 100644 --- a/Headers/gnustep/gui/NSActionCell.h +++ b/Headers/gnustep/gui/NSActionCell.h @@ -31,7 +31,7 @@ #include -@interface NSActionCell : NSCell +@interface NSActionCell : NSCell { // Attributes int tag; diff --git a/Headers/gnustep/gui/NSApplication.h b/Headers/gnustep/gui/NSApplication.h index c52768b43..1ab61f02b 100644 --- a/Headers/gnustep/gui/NSApplication.h +++ b/Headers/gnustep/gui/NSApplication.h @@ -31,6 +31,8 @@ #include +#define USE_RUN_LOOP 1 + @class NSArray; @class NSMutableArray; @class NSString; @@ -277,6 +279,9 @@ extern NSString *NSEventTrackingRunLoopMode; // handle a non-translated event - (void)handleNullEvent; +/* Set up the run loop input sources for a given mode */ +- (void)setupRunLoopInputSourcesForMode:(NSString*)mode; + @end @interface NSObject (NSServicesRequests) diff --git a/Headers/gnustep/gui/NSButtonCell.h b/Headers/gnustep/gui/NSButtonCell.h index 103ae2a94..1b700382a 100644 --- a/Headers/gnustep/gui/NSButtonCell.h +++ b/Headers/gnustep/gui/NSButtonCell.h @@ -44,7 +44,7 @@ typedef enum _NSButtonType { NSMomentaryLight } NSButtonType; -@interface NSButtonCell : NSActionCell +@interface NSButtonCell : NSActionCell { // Attributes NSString *altContents; diff --git a/Headers/gnustep/gui/NSCell.h b/Headers/gnustep/gui/NSCell.h index 3d53d1cc5..48d07c7d1 100644 --- a/Headers/gnustep/gui/NSCell.h +++ b/Headers/gnustep/gui/NSCell.h @@ -94,7 +94,7 @@ enum { NSChangeBackgroundCellMask = 8 }; -@interface NSCell : NSObject +@interface NSCell : NSObject { // Attributes NSString *contents; diff --git a/Headers/gnustep/gui/NSFont.h b/Headers/gnustep/gui/NSFont.h index dadfc007d..007e98267 100644 --- a/Headers/gnustep/gui/NSFont.h +++ b/Headers/gnustep/gui/NSFont.h @@ -6,7 +6,7 @@ Copyright (C) 1996 Free Software Foundation, Inc. Author: Scott Christley - Author: Ovidiu Predescu + Author: Ovidiu Predescu Date: 1996, 1997 This file is part of the GNUstep GUI Library. diff --git a/Headers/gnustep/gui/NSForm.h b/Headers/gnustep/gui/NSForm.h index a0b2e83dd..63c55c8cc 100644 --- a/Headers/gnustep/gui/NSForm.h +++ b/Headers/gnustep/gui/NSForm.h @@ -5,9 +5,9 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Scott Christley - Date: 1996 - + Author: Ovidiu Predescu + Date: March 1997 + This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or @@ -35,15 +35,12 @@ @class NSFont; @interface NSForm : NSMatrix -{ - // Attributes -} // // Laying Out the Form // -- (NSFormCell *)addEntry:(NSString *)title; -- (NSFormCell *)insertEntry:(NSString *)title +- (NSFormCell*)addEntry:(NSString*)title; +- (NSFormCell*)insertEntry:(NSString*)title atIndex:(int)index; - (void)removeEntryAtIndex:(int)index; - (void)setInterlineSpacing:(float)spacing; @@ -60,15 +57,9 @@ - (void)setBezeled:(BOOL)flag; - (void)setBordered:(BOOL)flag; - (void)setTextAlignment:(int)mode; -- (void)setTextFont:(NSFont *)fontObject; +- (void)setTextFont:(NSFont*)fontObject; - (void)setTitleAlignment:(NSTextAlignment)mode; -- (void)setTitleFont:(NSFont *)fontObject; - -// -// Setting the Cell Class -// -+ (Class)cellClass; -+ (void)setCellClass:(Class)classId; +- (void)setTitleFont:(NSFont*)fontObject; // // Getting a Cell @@ -90,12 +81,6 @@ // - (void)setEntryWidth:(float)width; -// -// NSCoding protocol -// -- (void)encodeWithCoder:aCoder; -- initWithCoder:aDecoder; - @end #endif // _GNUstep_H_NSForm diff --git a/Headers/gnustep/gui/NSFormCell.h b/Headers/gnustep/gui/NSFormCell.h index 0f478a8fe..6e01b549d 100644 --- a/Headers/gnustep/gui/NSFormCell.h +++ b/Headers/gnustep/gui/NSFormCell.h @@ -5,8 +5,8 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Scott Christley - Date: 1996 + Author: Ovidiu Predescu + Date: March 1997 This file is part of the GNUstep GUI Library. @@ -31,21 +31,14 @@ #include +@class NSTextFieldCell; + @interface NSFormCell : NSActionCell { - // Attributes + float titleWidth; + NSTextFieldCell* textCell; } -// -// Initializing an NSFormCell -// -- (id)initTextCell:(NSString *)aString; - -// -// Determining an NSFormCell's Size -// -- (NSSize)cellSizeForBounds:(NSRect)aRect; - // // Determining Graphic Attributes // @@ -54,13 +47,13 @@ // // Modifying the Title // -- (void)setTitle:(NSString *)aString; +- (void)setTitle:(NSString*)aString; - (void)setTitleAlignment:(NSTextAlignment)mode; -- (void)setTitleFont:(NSFont *)fontObject; +- (void)setTitleFont:(NSFont*)fontObject; - (void)setTitleWidth:(float)width; -- (NSString *)title; +- (NSString*)title; - (NSTextAlignment)titleAlignment; -- (NSFont *)titleFont; +- (NSFont*)titleFont; - (float)titleWidth; - (float)titleWidth:(NSSize)aSize; @@ -68,7 +61,7 @@ // Displaying // - (void)drawInteriorWithFrame:(NSRect)cellFrame - inView:(NSView *)controlView; + inView:(NSView*)controlView; // // NSCoding protocol diff --git a/Headers/gnustep/gui/NSGraphics.h b/Headers/gnustep/gui/NSGraphics.h index d83ab8769..ed9d92bad 100644 --- a/Headers/gnustep/gui/NSGraphics.h +++ b/Headers/gnustep/gui/NSGraphics.h @@ -3,7 +3,7 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Ovidiu Predescu + Author: Ovidiu Predescu Date: February 1997 This file is part of the GNUstep GUI Library. diff --git a/Headers/gnustep/gui/NSMatrix.h b/Headers/gnustep/gui/NSMatrix.h index a02a3381d..1fb2b1bb9 100644 --- a/Headers/gnustep/gui/NSMatrix.h +++ b/Headers/gnustep/gui/NSMatrix.h @@ -1,14 +1,12 @@ /* NSMatrix.h - This is the Matrix class. This class corresponds to NSMatrix - of the OpenStep specification, but it also allows for rows - and columns of different sizes. - Copyright (C) 1996 Free Software Foundation, Inc. - Author: Pascal Forget - Date: 1996 + Author: Ovidiu Predescu + Date: March 1997 + A completely rewritten version of the original source by Pascal Forget and + Scott Christley. This file is part of the GNUstep GUI Library. @@ -51,26 +49,31 @@ typedef enum _NSMatrixMode { @interface NSMatrix : NSControl { - // Attributes - NSMutableArray *rows; - NSMutableArray *col_widths; - NSMutableArray *row_heights; - int num_cols; - int num_rows; - NSCell *cell_prototype; - NSSize inter_cell; - Class cell_class; - BOOL allows_empty_selection; - BOOL selection_by_rect; - BOOL draws_background; - BOOL draws_cell_background; - NSMutableArray *selected_cells; - BOOL autoscroll; - BOOL scrollable; - BOOL autosize; - NSMatrixMode mode; - SEL double_action; - SEL error_action; + NSMutableArray* cells; + NSMatrixMode mode; + int numRows; + int numCols; + Class cellClass; + id cellPrototype; + NSSize cellSize; + NSSize intercell; + NSColor* backgroundColor; + NSColor* cellBackgroundColor; + id delegate; + id target; + SEL action; + SEL doubleAction; + SEL errorAction; + id selectedCell; + int selectedRow; + int selectedColumn; + void* selectedCells; + BOOL allowsEmptySelection; + BOOL selectionByRect; + BOOL drawsBackground; + BOOL drawsCellBackground; + BOOL autosizesCells; + BOOL autoscroll; } // @@ -147,6 +150,8 @@ typedef enum _NSMatrixMode { - (void)sortUsingFunction:(int (*)(id element1, id element2, void *userData))comparator context:(void *)context; - (void)sortUsingSelector:(SEL)comparator; +- (int)numberOfColumns; +- (int)numberOfRows; // // Finding Matrix Coordinates @@ -258,8 +263,11 @@ typedef enum _NSMatrixMode { // //Target and Action // -- (SEL)doubleAction; +- (void)setAction:(SEL)aSelector; +- (SEL)action; - (void)setDoubleAction:(SEL)aSelector; +- (SEL)doubleAction; +- (void)setErrorAction:(SEL)aSelector; - (SEL)errorAction; - (BOOL)sendAction; - (void)sendAction:(SEL)aSelector @@ -281,12 +289,6 @@ typedef enum _NSMatrixMode { // - (void)resetCursorRects; -// -// NSCoding protocol -// -- (void)encodeWithCoder:aCoder; -- initWithCoder:aDecoder; - @end #endif // _GNUstep_H_NSMatrix diff --git a/Source/Makefile.in b/Source/Makefile.in index 16184f07b..e5ebe02ee 100644 --- a/Source/Makefile.in +++ b/Source/Makefile.in @@ -53,7 +53,6 @@ ALL_CFLAGS = $(ALL_CPPFLAGS) $(CFLAGS) DEFS = -DGNUSTEP_INSTALL_LIBDIR=\"$(gnustep_libdir)\" @DEFS@ GCC_LIB = -OBJC_LIB = -lobjc SYS_LIBS = ADD_LIBS = @LIBS@ @@ -236,14 +235,14 @@ OBJS = $(OBJS_WITHOUT_INIT) .SUFFIXES: .m .m$(oext): - $(CC) -c $(ALL_CFLAGS) $(DEFS) -o $@ $< + $(CC) @OBJC_RUNTIME_FLAG@ -c $(ALL_CFLAGS) $(DEFS) -o $@ $< .c$(oext): $(CC) -c $(ALL_CFLAGS) $(DEFS) -o $@ $< # # libraries # -LIBS = $(GCC_LIB) $(OBJC_LIB) $(SYS_LIBS) $(ADD_LIBS) +LIBS = $(GCC_LIB) $(SYS_LIBS) $(ADD_LIBS) # # targets diff --git a/Source/NSActionCell.m b/Source/NSActionCell.m index 22715085b..6f5f49293 100644 --- a/Source/NSActionCell.m +++ b/Source/NSActionCell.m @@ -219,6 +219,17 @@ return tag; } +- (id)copyWithZone:(NSZone*)zone +{ + NSActionCell* c = [super copyWithZone:zone]; + + [c setTag:tag]; + [c setTarget:target]; + [c setAction:action]; + + return c; +} + // // NSCoding protocol // diff --git a/Source/NSApplication.m b/Source/NSApplication.m index 5f19f2e5a..ff292f7b9 100644 --- a/Source/NSApplication.m +++ b/Source/NSApplication.m @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -172,6 +173,12 @@ NSString *NSApplicationWillUpdateNotification = @"ApplicationWillUpdate"; // [self setNextResponder:NULL]; + /* Set up the run loop object for the current thread */ + [self setupRunLoopInputSourcesForMode:NSDefaultRunLoopMode]; + [self setupRunLoopInputSourcesForMode:NSConnectionReplyMode]; + [self setupRunLoopInputSourcesForMode:NSModalPanelRunLoopMode]; + [self setupRunLoopInputSourcesForMode:NSEventTrackingRunLoopMode]; + return self; } @@ -267,9 +274,10 @@ NSString *NSApplicationWillUpdateNotification = @"ApplicationWillUpdate"; do { - e = [self nextEventMatchingMask:NSAnyEventMask untilDate:nil - inMode:nil dequeue:YES]; - if (e != gnustep_gui_null_event) + e = [self nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSDefaultRunLoopMode dequeue:YES]; + if (e) [self sendEvent: e]; else { @@ -447,14 +455,16 @@ NSString *NSApplicationWillUpdateNotification = @"ApplicationWillUpdate"; if ([event_queue count]) { j = [event_queue count]; - for (i = j-1;i >= 0; --i) +// for (i = j-1;i >= 0; --i) + for (i = 0; i < j; i++) { e = [event_queue objectAtIndex: i]; if ([self event: e matchMask: mask]) { + [e retain]; [event_queue removeObjectAtIndex: i]; [self setCurrentEvent: e]; - return e; + return [e autorelease]; } } } @@ -463,18 +473,39 @@ NSString *NSApplicationWillUpdateNotification = @"ApplicationWillUpdate"; done = NO; while (!done) { - e = [self getNextEvent]; +#if USE_RUN_LOOP + NSRunLoop* currentLoop = [NSRunLoop currentRunLoop]; + NSDate* limitDate = [currentLoop limitDateForMode:mode]; - // Check mask - if ([self event: e matchMask: mask]) - { - if (e) - { - [event_queue removeObject: e]; - } - done = YES; + if (!expiration) + expiration = [NSDate distantFuture]; + + if (limitDate) + limitDate = [expiration earlierDate:limitDate]; + else + limitDate = expiration; + +// NSLog (@"calling runMode:beforeDate:"); + [currentLoop runMode:mode beforeDate:limitDate]; +// NSLog (@"return from runMode:beforeDate:"); +#else + e = [self getNextEvent]; +#endif + + if ([event_queue count]) { + e = [[event_queue lastObject] retain]; + + // Check mask + if ([self event: e matchMask: mask]) + { + if (e) + { + [event_queue removeObject: e]; + } + done = YES; + } } - } + } // Unhide the cursor if necessary // but only if its not a null event @@ -495,7 +526,7 @@ NSString *NSApplicationWillUpdateNotification = @"ApplicationWillUpdate"; } [self setCurrentEvent: e]; - return e; + return [e autorelease]; } - (NSEvent *)peekEventMatchingMask:(unsigned int)mask @@ -1129,4 +1160,7 @@ NSString *NSApplicationWillUpdateNotification = @"ApplicationWillUpdate"; - (void)handleNullEvent {} +- (void)setupRunLoopInputSourcesForMode:(NSString*)mode +{} + @end diff --git a/Source/NSButton.m b/Source/NSButton.m index 1684857a9..0f6c1eb41 100644 --- a/Source/NSButton.m +++ b/Source/NSButton.m @@ -293,7 +293,7 @@ id gnustep_gui_nsbutton_class = nil; return; // capture mouse - [[self window] captureMouse: self]; +// [[self window] captureMouse: self]; [self lockFocus]; done = NO; @@ -311,12 +311,12 @@ id gnustep_gui_nsbutton_class = nil; { NSDebugLog(@"NSButton process another event\n"); e = [theApp nextEventMatchingMask:event_mask untilDate:nil - inMode:nil dequeue:YES]; + inMode:NSEventTrackingRunLoopMode dequeue:YES]; } } // Release mouse - [[self window] releaseMouse: self]; +// [[self window] releaseMouse: self]; // If the mouse went up in the button if (mouseUp) diff --git a/Source/NSButtonCell.m b/Source/NSButtonCell.m index 6430e8f28..a24eaa39e 100644 --- a/Source/NSButtonCell.m +++ b/Source/NSButtonCell.m @@ -319,11 +319,6 @@ control_view = controlView; } -+ (BOOL)prefersTrackingUntilMouseUp -{ - return YES; -} - // // Simulating a Click // @@ -331,6 +326,22 @@ { } +- (id)copyWithZone:(NSZone*)zone +{ + NSButtonCell* c = [super copyWithZone:zone]; + + [c setAlternateTitle:altContents]; + [c setAlternateImage:altImage]; + [c setKeyEquivalent:keyEquivalent]; + [c setKeyEquivalentFont:keyEquivalentFont]; + [c setKeyEquivalentModifierMask:keyEquivalentModifierMask]; + [c setTransparent:transparent]; + c->highlightsByMask = highlightsByMask; + c->showAltStateMask = showAltStateMask; + + return c; +} + // // NSCoding protocol // diff --git a/Source/NSCell.m b/Source/NSCell.m index 9588505fd..bfba1066a 100644 --- a/Source/NSCell.m +++ b/Source/NSCell.m @@ -64,9 +64,8 @@ // // Initializing an NSCell // -- init +- _init { - [super init]; cell_type = NSNullCellType; cell_image = nil; cell_font = nil; @@ -86,9 +85,16 @@ return self; } +- init +{ + self = [super init]; + [self _init]; + return self; +} + - (id)initImageCell:(NSImage *)anImage { - [super init]; + [self _init]; // Not an image class --then forget it if (![anImage isKindOfClass:[NSImage class]]) @@ -98,24 +104,12 @@ cell_image = [anImage retain]; image_position = NSImageOnly; cell_font = [[NSFont userFontOfSize:16] retain]; - cell_state = NO; - cell_highlighted = NO; - cell_enabled = YES; - cell_editable = NO; - cell_bordered = NO; - cell_bezeled = NO; - cell_scrollable = NO; - cell_selectable = NO; - cell_continuous = NO; - cell_float_autorange = NO; - cell_float_left = 0; - cell_float_right = 0; return self; } - (id)initTextCell:(NSString *)aString { - [super init]; + [self _init]; // Not a string class --then forget it //if (![aString isKindOfClass:[NSString class]]) @@ -127,15 +121,6 @@ text_align = NSCenterTextAlignment; cell_image = nil; image_position = NSNoImage; - cell_state = NO; - cell_highlighted = NO; - cell_enabled = YES; - cell_editable = NO; - cell_bordered = NO; - cell_bezeled = NO; - cell_scrollable = NO; - cell_selectable = NO; - cell_continuous = NO; cell_float_autorange = YES; cell_float_left = 0; cell_float_right = 6; @@ -649,7 +634,7 @@ { last_point = point; e = [theApp nextEventMatchingMask:event_mask untilDate:nil - inMode:nil dequeue:YES]; + inMode:NSEventTrackingRunLoopMode dequeue:YES]; location = [e locationInWindow]; point = [controlView convertPoint: location fromView: nil]; NSDebugLog(@"NSCell location %f %f\n", location.x, location.y); @@ -751,6 +736,36 @@ - (void)setRepresentedObject:(id)anObject {} +- (id)copyWithZone:(NSZone*)zone +{ + NSCell* c = NSAllocateObject (isa, 0, zone); + + [c setStringValue:contents]; + [c setImage:cell_image]; + [c setFont:cell_font]; + [c setState:cell_state]; + c->cell_highlighted = cell_highlighted; + [c setEnabled:cell_enabled]; + [c setEditable:cell_editable]; + [c setBordered:cell_bordered]; + [c setBezeled:cell_bezeled]; + [c setScrollable:cell_scrollable]; + [c setSelectable:cell_selectable]; + [c setContinuous:cell_continuous]; + [c setFloatingPointFormat:cell_float_autorange + left:cell_float_left + right:cell_float_right]; + c->image_position = image_position; + [c setType:cell_type]; + [c setAlignment:text_align]; + [c setEntryType:entry_type]; + c->control_view = control_view; + c->cell_size = cell_size; + c->represented_object = [represented_object retain]; + + return c; +} + // // NSCoding protocol // diff --git a/Source/NSEvent.m b/Source/NSEvent.m index 1975289d6..f54ab3afc 100644 --- a/Source/NSEvent.m +++ b/Source/NSEvent.m @@ -6,6 +6,7 @@ Copyright (C) 1996 Free Software Foundation, Inc. Author: Scott Christley + Author: Ovidiu Predescu Date: 1996 This file is part of the GNUstep GUI Library. @@ -26,11 +27,23 @@ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include +#include +#include +#include +#include +#include + #include #include @implementation NSEvent +// Class variables +static NSMutableDictionary* timers = nil; +static NSRecursiveLock* timersLock = nil; + // // Private methods // @@ -142,6 +155,8 @@ // Initial version [self setVersion:1]; + timers = [NSMutableDictionary new]; + timersLock = [NSRecursiveLock new]; } } @@ -287,10 +302,95 @@ // + (void)startPeriodicEventsAfterDelay:(NSTimeInterval)delaySeconds withPeriod:(NSTimeInterval)periodSeconds -{} +{ + NSTimer* timer; + NSThread* currentThread = [NSThread currentThread]; + + [timersLock lock]; + + NSDebugLog (@"startPeriodicEventsAfterDelay:withPeriod:"); + /* Check for any pending timer for this thread */ + if ([timers objectForKey:currentThread]) + [NSException raise:NSInternalInconsistencyException + format:@"Periodic events are already being generated for " + @"this thread %x", currentThread]; + + /* If the delay time is 0 then register a timer right now. Otherwise register + a timer with no repeat that when fired registers the real timer */ + if (!delaySeconds) + timer = [NSTimer timerWithTimeInterval:periodSeconds + target:self + selector:@selector(_timerFired:) + userInfo:nil + repeats:YES]; + else + timer = [NSTimer timerWithTimeInterval:delaySeconds + target:self + selector:@selector(_registerRealTimer:) + userInfo:[NSNumber numberWithDouble:periodSeconds] + repeats:NO]; + + [[NSRunLoop currentRunLoop] + addTimer:timer forMode:NSEventTrackingRunLoopMode]; + [timers setObject:timer forKey:currentThread]; + + [timersLock unlock]; +} + ++ (void)_timerFired:(NSTimer*)timer +{ + NSEvent* periodicEvent + = [self otherEventWithType:NSPeriodic + location:NSZeroPoint + modifierFlags:0 + timestamp:[[NSDate date] timeIntervalSinceReferenceDate] + windowNumber:0 + context:[NSApp context] + subtype:0 + data1:0 + data2:0]; + + NSDebugLog (@"_timerFired:"); + [NSApp postEvent:periodicEvent atStart:NO]; +} + ++ (void)_registerRealTimer:(NSTimer*)timer +{ + NSTimeInterval periodSeconds = [[timer userInfo] doubleValue]; + NSTimer* realTimer = [NSTimer timerWithTimeInterval:periodSeconds + target:self + selector:@selector(_timerFired:) + userInfo:nil + repeats:YES]; + NSThread* currentThread = [NSThread currentThread]; + + NSDebugLog (@"_registerRealTimer:"); + [timersLock lock]; + + /* Add the real timer into the timers dictionary and to the run loop */ + [timers setObject:realTimer forKey:currentThread]; + [[NSRunLoop currentRunLoop] + addTimer:realTimer forMode:NSEventTrackingRunLoopMode]; + + [timersLock unlock]; +} + (void)stopPeriodicEvents -{} +{ + NSTimer* timer; + NSThread* currentThread; + + NSDebugLog (@"stopPeriodicEvents"); + [timersLock lock]; + + currentThread = [NSThread currentThread]; + /* Remove any existing timer for this thread */ + timer = [timers objectForKey:currentThread]; + [timer invalidate]; + [timers removeObjectForKey:currentThread]; + + [timersLock unlock]; +} // // Instance methods diff --git a/Source/NSFont.m b/Source/NSFont.m index 91b1dfa32..1e7bfec36 100644 --- a/Source/NSFont.m +++ b/Source/NSFont.m @@ -5,7 +5,7 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Ovidiu Predescu + Author: Ovidiu Predescu Date: February 1997 A completely rewritten version of the original source by Scott Christley. diff --git a/Source/NSForm.m b/Source/NSForm.m index d310c6f11..bebb3969f 100644 --- a/Source/NSForm.m +++ b/Source/NSForm.m @@ -1,12 +1,12 @@ -/* +/* NSForm.m Form class, a text field with a label Copyright (C) 1996 Free Software Foundation, Inc. - Author: Scott Christley - Date: 1996 + Author: Ovidiu Predescu + Date: March 1997 This file is part of the GNUstep GUI Library. @@ -27,103 +27,145 @@ */ #include +#include @implementation NSForm -// -// Laying Out the Form -// -- (NSFormCell *)addEntry:(NSString *)title +- (NSFormCell*)addEntry:(NSString*)title { - return nil; + return [self insertEntry:title atIndex:[self numberOfRows]]; } -- (NSFormCell *)insertEntry:(NSString *)title +- (NSFormCell*)insertEntry:(NSString*)title atIndex:(int)index { - return nil; + [self insertRow:index]; + return [self cellAtRow:index column:0]; } - (void)removeEntryAtIndex:(int)index -{} +{ + [self removeRow:index]; +} + +- (void)setBezeled:(BOOL)flag +{ + int i, count = [self numberOfRows]; + + /* Set the bezeled attribute to the cell prototype */ + [[self prototype] setBezeled:flag]; + + for (i = 0; i < count; i++) + [[self cellAtRow:i column:0] setBezeled:flag]; +} + +- (void)setBordered:(BOOL)flag +{ + int i, count = [self numberOfRows]; + + /* Set the bordered attribute to the cell prototype */ + [[self prototype] setBordered:flag]; + + for (i = 0; i < count; i++) + [[self cellAtRow:i column:0] setBordered:flag]; +} + +- (void)setEntryWidth:(float)width +{ + NSSize size = [self cellSize]; + + size.width = width; + [self setCellSize:size]; +} - (void)setInterlineSpacing:(float)spacing -{} +{ + [self setIntercellSpacing:NSMakeSize(0, spacing)]; +} + +/* For the title attributes we use the corresponding attributes from the cell. + For the text attributes we use instead the attributes inherited from the + NSCell class. */ +- (void)setTitleAlignment:(NSTextAlignment)aMode +{ + int i, count = [self numberOfRows]; + + /* Set the title alignment attribute to the cell prototype */ + [[self prototype] setTitleAlignment:aMode]; + + for (i = 0; i < count; i++) + [[self cellAtRow:i column:0] setTitleAlignment:aMode]; +} + +- (void)setTextAlignment:(int)aMode +{ + int i, count = [self numberOfRows]; + + /* Set the text alignment attribute to the cell prototype */ + [[self prototype] setAlignment:aMode]; + + for (i = 0; i < count; i++) + [[self cellAtRow:i column:0] setAlignment:aMode]; +} + +- (void)setTitleFont:(NSFont*)fontObject +{ + int i, count = [self numberOfRows]; + + /* Set the title font attribute to the cell prototype */ + [[self prototype] setTitleFont:fontObject]; + + for (i = 0; i < count; i++) + [[self cellAtRow:i column:0] setTitleFont:fontObject]; +} + +- (void)setTextFont:(NSFont*)fontObject +{ + int i, count = [self numberOfRows]; + + /* Set the text font attribute to the cell prototype */ + [[self prototype] setFont:fontObject]; + + for (i = 0; i < count; i++) + [[self cellAtRow:i column:0] setFont:fontObject]; +} -// -// Finding Indices -// - (int)indexOfCellWithTag:(int)aTag { - return 0; + int i, count = [self numberOfRows]; + + for (i = 0; i < count; i++) + if ([[self cellAtRow:i column:0] tag] == aTag) + return i; + return -1; } - (int)indexOfSelectedItem { - return 0; + return [self selectedRow]; } -// -// Modifying Graphic Attributes -// -- (void)setBezeled:(BOOL)flag -{} - -- (void)setBordered:(BOOL)flag -{} - -- (void)setTextAlignment:(int)mode -{} - -- (void)setTextFont:(NSFont *)fontObject -{} - -- (void)setTitleAlignment:(NSTextAlignment)mode -{} - -- (void)setTitleFont:(NSFont *)fontObject -{} - -// -// Setting the Cell Class -// -+ (Class)cellClass -{ - return nil; -} - -+ (void)setCellClass:(Class)classId -{} - -// -// Getting a Cell -// - (id)cellAtIndex:(int)index { - return nil; + return [self cellAtRow:index column:0]; } -// -// Displaying a Cell -// - (void)drawCellAtIndex:(int)index -{} +{ + id theCell = [self cellAtIndex:index]; + + [theCell drawWithFrame:[self cellFrameAtRow:index column:0] + inView:self]; +} + +- (void)drawCellAtRow:(int)row column:(int)column +{ + [self drawCellAtIndex:row]; +} -// -// Editing Text -// - (void)selectTextAtIndex:(int)index {} -// -// Resizing the Form -// -- (void)setEntryWidth:(float)width -{} - -// -// NSCoding protocol -// - (void)encodeWithCoder:aCoder { [super encodeWithCoder:aCoder]; diff --git a/Source/NSFormCell.m b/Source/NSFormCell.m index 17dd8e3f3..057dd6b9b 100644 --- a/Source/NSFormCell.m +++ b/Source/NSFormCell.m @@ -5,8 +5,8 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Scott Christley - Date: 1996 + Author: Ovidiu Predescu + Date: March 1997 This file is part of the GNUstep GUI Library. @@ -27,83 +27,101 @@ */ #include +#include +#include @implementation NSFormCell -// -// Initializing an NSFormCell -// -- (id)initTextCell:(NSString *)aString +/* The title attributes are those inherited from the NSActionCell class. */ + +- init { - return nil; + self = [super init]; + [self setBordered:NO]; + [self setBezeled:NO]; + titleWidth = -1; + textCell = [NSTextFieldCell new]; + [textCell setBordered:YES]; + [textCell setBezeled:YES]; + return self; } -// -// Determining an NSFormCell's Size -// -- (NSSize)cellSizeForBounds:(NSRect)aRect +- (void)dealloc { - return NSZeroSize; + [textCell release]; + [super dealloc]; } -// -// Determining Graphic Attributes -// - (BOOL)isOpaque { - return NO; + return [super isOpaque] && [textCell isOpaque]; } -// -// Modifying the Title -// -- (void)setTitle:(NSString *)aString -{} +- (void)setTitle:(NSString*)aString +{ + [self setStringValue:aString]; +} - (void)setTitleAlignment:(NSTextAlignment)mode -{} +{ + [self setAlignment:mode]; +} -- (void)setTitleFont:(NSFont *)fontObject -{} +- (void)setTitleFont:(NSFont*)fontObject +{ + [self setFont:fontObject]; +} - (void)setTitleWidth:(float)width -{} - -- (NSString *)title { - return nil; + titleWidth = width; +} + +- (NSString*)title +{ + return [self stringValue]; } - (NSTextAlignment)titleAlignment { - return 0; + return [self alignment]; } -- (NSFont *)titleFont +- (NSFont*)titleFont { - return nil; + return [self font]; } - (float)titleWidth { - return 0; + if (titleWidth < 0) + return [[self font] widthOfString:[self title]]; + else + return titleWidth; } -- (float)titleWidth:(NSSize)aSize +- (float)titleWidth:(NSSize)size { + // TODO return 0; } -// -// Displaying -// - (void)drawInteriorWithFrame:(NSRect)cellFrame - inView:(NSView *)controlView -{} + inView:(NSView*)controlView +{ + NSRect titleRect = cellFrame; + NSRect textRect; + + titleRect.size.width = [self titleWidth] + 4; + [super drawInteriorWithFrame:titleRect inView:controlView]; + + textRect.origin.x = cellFrame.origin.x + titleRect.size.width; + textRect.origin.y = cellFrame.origin.y; + textRect.size.width = cellFrame.size.width - titleRect.size.width; + textRect.size.height = cellFrame.size.height; + [textCell drawInteriorWithFrame:textRect inView:controlView]; +} -// -// NSCoding protocol -// - (void)encodeWithCoder:aCoder { [super encodeWithCoder:aCoder]; diff --git a/Source/NSMatrix.m b/Source/NSMatrix.m index fcff9ac82..cdae72556 100644 --- a/Source/NSMatrix.m +++ b/Source/NSMatrix.m @@ -5,9 +5,10 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Pascal Forget - Scott Christley - Date: 1996 + Author: Ovidiu Predescu + Date: March 1997 + A completely rewritten version of the original source by Pascal Forget and + Scott Christley. This file is part of the GNUstep GUI Library. @@ -27,1273 +28,951 @@ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include + #include #include -#include +#include #include #include #include +#include -#define GNU_DEFAULT_CELL_HEIGHT 20 +/* Define the following symbol when NSView will support flipped views */ +//#define HAS_FLIPPED_VIEWS 1 -// -// Class variables -// -static Class NSMATRIX_DEFAULT_CELL_CLASS = nil; +#define ASSIGN(a, b) \ + [b retain]; \ + [a release]; \ + a = b; + +#ifdef MIN +# undef MIN +#endif +# define MIN(a, b) \ + ({typedef _ta = (a), _tb = (b); \ + _ta _a = (a); _tb _b = (b); \ + _a < _b ? _a : _b; }) + +#ifdef MAX +# undef MAX +#endif +# define MAX(a, b) \ + ({typedef _ta = (a), _tb = (b); \ + _ta _a = (a); _tb _b = (b); \ + _a > _b ? _a : _b; }) + +#ifdef ABS +# undef ABS +#endif +# define ABS(x) \ + ({typedef _tx = (x); \ + _tx _x = (x); \ + _x >= 0 ? _x : -_x; }) + +#define SIGN(x) \ + ({typedef _tx = (x); \ + _tx _x = (x); \ + _x > 0 ? 1 : (_x == 0 ? 0 : -1); }) + +#define FREE(p) do { if (p) free (p); } while (0) + +#define POINT_FROM_INDEX(index) \ + ({MPoint point = { index % numCols, index / numCols }; point; }) + +#define INDEX_FROM_POINT(point) \ + (point.y * numCols + point.x) + + +typedef struct _tMatrix { + int numRows, numCols; + int allocatedRows, allocatedCols; + BOOL** matrix; +} *tMatrix; + +static tMatrix newMatrix (int numRows, int numCols) +{ + int rows = (numRows ? numRows : 1); + int cols = (numCols ? numCols : 1); + tMatrix m = malloc (sizeof (struct _tMatrix)); + int i; + + m->matrix = malloc (rows * sizeof (BOOL*)); + for (i = 0; i < rows; i++) + m->matrix[i] = calloc (cols, sizeof (BOOL)); + + m->allocatedRows = rows; + m->allocatedCols = cols; + m->numRows = numRows; + m->numCols = numCols; + + return m; +} + +static void freeMatrix (tMatrix m) +{ + int i; + + for (i = 0; i < m->allocatedRows; i++) + FREE (m->matrix[i]); + FREE (m->matrix); + FREE (m); +} + +/* Grow the matrix to some arbitrary dimensions */ +static void growMatrix (tMatrix m, int numRows, int numCols) +{ + int i, j; + + if (numCols > m->allocatedCols) { + /* Grow the existing rows to numCols */ + for (i = 0; i < numRows; i++) { + m->matrix[i] = realloc (m->matrix[i], numCols * sizeof (BOOL)); + for (j = m->allocatedCols; j < numCols; j++) + m->matrix[i][j] = NO; + } + m->allocatedCols = numCols; + } + + if (numRows > m->allocatedRows) { + /* Grow the vector that keeps the rows */ + m->matrix = realloc (m->matrix, numRows * sizeof (BOOL*)); + + /* Allocate the rows up to allocatedRows that are NULL */ + for (i = 0; i < m->allocatedRows; i++) + if (!m->matrix[i]) + m->matrix[i] = calloc (m->allocatedCols, sizeof (BOOL)); + + /* Add the necessary rows */ + for (i = m->allocatedRows; i < numRows; i++) + m->matrix[i] = calloc (m->allocatedCols, sizeof (BOOL)); + m->allocatedRows = numRows; + } + + m->numRows = numRows; + m->numCols = numCols; +} + +static void insertRow (tMatrix m, int rowPosition) +{ + int rows = m->numRows + 1; + int i; + + /* Create space for the new rows if necessary */ + if (rows > m->allocatedRows) { + m->matrix = realloc (m->matrix, rows * sizeof (BOOL*)); + m->allocatedRows = rows; + } + + /* Make room for the new row */ + for (i = m->numRows - 1; i > rowPosition; i--) + m->matrix[i] = m->matrix[i - 1]; + + /* Allocate any NULL row that exists up to rowPosition */ + for (i = 0; i < rowPosition; i++) + if (!m->matrix[i]) + m->matrix[i] = calloc (m->allocatedCols, sizeof (BOOL)); + + /* Create the required row */ + m->matrix[rowPosition] = calloc (m->allocatedCols, sizeof (BOOL)); + + m->numRows++; +} + +static void insertColumn (tMatrix m, int colPosition) +{ + int cols = m->numCols + 1; + int i, j; + + /* First grow the rows to hold `cols' elements */ + if (cols > m->allocatedCols) { + for (i = 0; i < m->numRows; i++) + m->matrix[i] = realloc (m->matrix[i], cols * sizeof (BOOL)); + m->allocatedCols = cols; + } + + /* Now insert a new column between the rows, in the required position. + If it happens that a row is NULL create a new row with the maximum + number of columns for it. */ + for (i = 0; i < m->numRows; i++) { + BOOL* row = m->matrix[i]; + + if (!row) + m->matrix[i] = calloc (m->allocatedCols, sizeof (BOOL)); + else { + for (j = m->numCols - 1; j > colPosition; j--) + row[j] = row[j - 1]; + row[colPosition] = NO; + } + } + m->numCols++; +} + +static void removeRow (tMatrix m, int row) +{ + int i; + + /* Free the row and shrink the matrix by removing the row from it */ + FREE (m->matrix[row]); + m->matrix[row] = NULL; + for (i = row; i < m->numRows - 1; i++) + m->matrix[i] = m->matrix[i + 1]; + m->numRows--; + m->matrix[m->numRows] = NULL; +} + +static void removeColumn (tMatrix m, int column) +{ + int i, j; + + for (i = 0; i < m->numRows; i++) { + BOOL* row = m->matrix[i]; + + for (j = column; j < m->numCols - 1; j++) + row[j] = row[j + 1]; + row[m->numCols] = NO; + } + m->numCols--; +} + +/* Some stuff needed to compute the selection in the list mode. */ +typedef struct { + int x; + int y; +} MPoint; + +typedef struct { + int x; + int y; + int width; + int height; +} MRect; + +static inline MPoint MakePoint (int x, int y) +{ + MPoint point = { x, y }; + return point; +} + +@interface NSMatrix (PrivateMethods) + +/* Returns by reference the row and column of cell that is above or below or + to the left or to the right of point. `point' is in the matrix coordinates. + Returns NO if the point is outside the bounds of matrix, YES otherwise. + */ +- (BOOL)_getRow:(int*)row + column:(int*)column + forPoint:(NSPoint)point + above:(BOOL)aboveRequired + right:(BOOL)rightRequired + isBetweenCells:(BOOL*)isBetweenCells; +- (void)_selectRectUsingAnchor:(MPoint)anchor + last:(MPoint)last + current:(MPoint)current; +- (void)_setState:(int)state inRect:(MRect)rect; +- (void)_selectContinuousUsingAnchor:(MPoint)anchor + last:(MPoint)last + current:(MPoint)current; +- (void)_setState:(int)state startIndex:(int)start endIndex:(int)end; +@end + +enum { + DEFAULT_CELL_HEIGHT = 17, + DEFAULT_CELL_WIDTH = 100 +}; @implementation NSMatrix +/* Class variables */ +static Class defaultCellClass = nil; +static int mouseDownFlags = 0; + + (void)initialize { - if (self == [NSMatrix class]) - { - NSDebugLog(@"Initialize NSMatrix class\n"); + if (self == [NSMatrix class]) { + /* Set the initial version */ + [self setVersion: 1]; - // Set initial version - [self setVersion: 1]; - - // Set the default cell class - NSMATRIX_DEFAULT_CELL_CLASS = [NSCell class]; - } + /* Set the default cell class */ + defaultCellClass = [NSCell class]; + } } -// -// Initializing the NSMatrix Class -// + (Class)cellClass { - return NSMATRIX_DEFAULT_CELL_CLASS; + return defaultCellClass; } + (void)setCellClass:(Class)classId { - NSMATRIX_DEFAULT_CELL_CLASS = classId; + defaultCellClass = classId; } -// -// Initializing an NSMatrix Object -// -- (void)createInitialMatrix +- init +{ + return [self initWithFrame:NSZeroRect + mode:NSRadioModeMatrix + prototype:[[[isa cellClass] new] autorelease] + numberOfRows:0 + numberOfColumns:1]; +} + +- (id)initWithFrame:(NSRect)frameRect +{ + return [self initWithFrame:frameRect + mode:NSRadioModeMatrix + cellClass:[isa cellClass] + numberOfRows:0 + numberOfColumns:0]; +} + +- (id)initWithFrame:(NSRect)frameRect + mode:(int)aMode + cellClass:(Class)class + numberOfRows:(int)rowsHigh + numberOfColumns:(int)colsWide +{ + return [self initWithFrame:frameRect + mode:aMode + prototype:[[class new] autorelease] + numberOfRows:rowsHigh + numberOfColumns:colsWide]; +} + +- (id)initWithFrame:(NSRect)frameRect + mode:(int)aMode + prototype:(NSCell*)prototype + numberOfRows:(int)rows + numberOfColumns:(int)cols { - NSSize cs; int i, j; - id aRow, aFloat; - // Determine cell width and height for uniform cell size - cs.width = (frame.size.width - (inter_cell.width * (num_cols - 1))) - / num_cols; - cs.height = (frame.size.height - (inter_cell.height * (num_rows - 1))) - / num_rows; + ASSIGN(cellPrototype, prototype); - // Save cell widths and heights in arrays - aFloat = [NSNumber numberWithFloat: cs.height]; - for (i = 0;i < num_rows; ++i) - [row_heights addObject:aFloat]; - aFloat = [NSNumber numberWithFloat: cs.width]; - for (i = 0;i < num_cols; ++i) - [col_widths addObject:aFloat]; + cells = [[NSMutableArray alloc] initWithCapacity:rows]; + selectedCells = newMatrix (rows, cols); + for (i = 0; i < rows; i++) { + NSMutableArray* row = [NSMutableArray arrayWithCapacity:cols]; - for (i = 0;i < num_rows; ++i) - { - aRow = [NSMutableArray arrayWithCapacity: num_cols]; - [rows addObject: aRow]; - for (j = 0;j < num_cols; ++j) - { - if (cell_prototype != nil) - { - [(NSMutableArray *)aRow addObject: - [cell_prototype copy]]; - } - else - { - [(NSMutableArray *)aRow addObject: - [[cell_class alloc] init]]; - } - } + [cells addObject:row]; + for (j = 0; j < cols; j++) { + [row addObject:[[cellPrototype copy] autorelease]]; } -} + } -- (id)initWithFrame:(NSRect)frameRect -{ - return [self initWithFrame: frameRect - mode: NSTrackModeMatrix - cellClass: NSMATRIX_DEFAULT_CELL_CLASS - numberOfRows: 0 - numberOfColumns: 0]; -} - -- (id)initWithFrame:(NSRect)frameRect - mode:(int)aMode - cellClass:(Class)classId - numberOfRows:(int)rowsHigh - numberOfColumns:(int)colsWide -{ - NSDebugLog(@"NSMatrix start -initWithFrame: ..cellClass:\n"); - - [super initWithFrame:frameRect]; - - if (rowsHigh < 0) - { - NSLog(@"NSMatrix initWithFrame:mode: rows has to be >= 0.\n"); - NSLog(@"Will create matrix with 0 rows.\n"); - - num_rows = 0; - } - else - { - num_rows = rowsHigh; - } - - if (colsWide < 0) - { - NSLog(@"NSMatrix initWithFrame:mode: columns has to be >= 0.\n"); - NSLog(@"Will create matrix with 0 columns.\n"); - - num_cols = 0; - } - else - { - num_cols = colsWide; - } - - rows = [[NSMutableArray alloc] init]; - row_heights = [[NSMutableArray alloc] init]; - col_widths = [[NSMutableArray alloc] init]; - selected_cells = [[NSMutableArray alloc] init]; - inter_cell.width = inter_cell.height = 2; - allows_empty_selection = YES; - - cell_prototype = nil; - cell_class = classId; + numRows = rows; + numCols = cols; mode = aMode; + [self setFrame:frameRect]; - [self createInitialMatrix]; + cellSize = NSMakeSize(DEFAULT_CELL_WIDTH, DEFAULT_CELL_HEIGHT); + intercell = NSMakeSize(1, 1); + [self setBackgroundColor:[NSColor lightGrayColor]]; + [self setCellBackgroundColor:[NSColor lightGrayColor]]; + [self setSelectionByRect:YES]; + [self setAutosizesCells:YES]; + if (mode == NSRadioModeMatrix && numRows && numCols) { + selectedRow = selectedColumn = 0; + [self selectCellAtRow:0 column:0]; + } + else + selectedRow = selectedColumn = -1; - NSDebugLog(@"NSMatrix end -initWithFrame: ..cellClass:\n"); return self; } -- (id)initWithFrame:(NSRect)frameRect - mode:(int)aMode - prototype:(NSCell *)aCell - numberOfRows:(int)rowsHigh - numberOfColumns:(int)colsWide +- (void)dealloc { - [super initWithFrame:frameRect]; - - if (aCell == nil) - { - NSLog(@"NSMatrix "); - NSLog(@"initWithFrame:mode:prototype:numberOfRows:numberOfColumns: "); - NSLog(@"prototype can't be nil. "); - NSLog(@"Using NSCell as the default class.\n"); - - cell_prototype = nil; - - cell_class = [NSCell class]; - } - else - { - cell_prototype = [aCell retain]; - } - - return self; + [cells release]; + [cellPrototype release]; + [backgroundColor release]; + [cellBackgroundColor release]; + freeMatrix (selectedCells); + [super dealloc]; } -// -// Setting the Selection Mode -// -- (NSMatrixMode)mode -{ - return mode; -} - -- (void)setMode:(NSMatrixMode)aMode -{ - mode = aMode; -} - -// -// Configuring the NSMatrix -// -- (BOOL)allowsEmptySelection -{ - return allows_empty_selection; -} - -- (BOOL)isSelectionByRect -{ - return selection_by_rect; -} - -- (void)setAllowsEmptySelection:(BOOL)flag -{ - allows_empty_selection = flag; -} - -- (void)setSelectionByRect:(BOOL)flag -{ - selection_by_rect = flag; -} - -// -// Setting the Cell Class -// -- (Class)cellClass -{ - return cell_class; -} - -- (id)prototype -{ - return cell_prototype; -} - -- (void)setCellClass:(Class)classId -{ - cell_class = classId; -} - -- (void)setPrototype:(NSCell *)aCell -{ - cell_prototype = [aCell retain]; -} - -// -// Laying Out the NSMatrix -// - (void)addColumn { - int i; - NSNumber *anInt; - NSMutableArray *aRow; - - if (num_rows <= 0) - { - [rows addObject:[[NSMutableArray alloc] init]]; - num_rows = 1; - - [row_heights removeAllObjects]; - anInt = [NSNumber numberWithInt: GNU_DEFAULT_CELL_HEIGHT]; - [row_heights addObject:anInt]; - } - - for (i=0; i num_rows) - { - NSDebugLog(@"NSMatrix add more rows %d %d\n", nrows, num_rows); - new_rows = nrows - num_rows; - for (i = 0; i < new_rows; ++i) - { - a = [[NSMutableArray alloc] init]; - [rows addObject: a]; - ++num_rows; - } - } - ++num_cols; - NSDebugLog(@"NSMatrix rows %d cols %d\n", num_rows, num_cols); - - // Determine cell width and height for uniform cell size - cs.width = (frame.size.width - (inter_cell.width * (num_cols - 1))) - / num_cols; - cs.height = (frame.size.height - (inter_cell.height * (num_rows - 1))) - / num_rows; - - // Save cell widths and heights in arrays - aFloat = [NSNumber numberWithFloat: cs.height]; - for (i = 0;i < nrows; ++i) - [row_heights addObject:aFloat]; - aFloat = [NSNumber numberWithFloat: cs.width]; - [col_widths addObject:aFloat]; - NSDebugLog(@"NSMatrix cell size %f %f\n", cs.width, cs.height); - - e = [cellArray objectEnumerator]; - o = [e nextObject]; - re = [rows objectEnumerator]; - aRow = [re nextObject]; - while (o) - { - [aRow addObject: o]; - [o retain]; - o = [e nextObject]; - aRow = [re nextObject]; - } + [self insertColumn:numCols withCells:cellArray]; } - (void)addRow { - int i; - NSNumber *anInt; - NSMutableArray *newRow = [[NSMutableArray alloc] init]; - - if (cell_prototype != nil) - { - [newRow addObject:[cell_prototype copy]]; - } - else - { - [newRow addObject:[[cell_class alloc] init]]; - } - - if (num_cols > 0) - { - for (i=1; i numCols) + [self renewRows:(numRows == 0 ? 1 : numRows) columns:column]; + else if (numRows == 0) { + numRows = 1; + [cells addObject:[NSMutableArray array]]; + } - // No array then forget the insert - if (!cellArray) - return; + numCols++; + for (i = 0; i < numRows; i++) + [self makeCellAtRow:i column:column]; + insertColumn (selectedCells, column); - a = [[NSMutableArray alloc] init]; - [rows addObject: a]; - ++num_rows; - ncols = [cellArray count]; + if (mode == NSRadioModeMatrix && !allowsEmptySelection && !selectedCell) + [self selectCellAtRow:0 column:0]; +} - // Determine cell width and height for uniform cell size - cs.width = (frame.size.width - (inter_cell.width * (ncols - 1))) - / ncols; - cs.height = (frame.size.height - (inter_cell.height * (num_rows - 1))) - / num_rows; +- (void)insertColumn:(int)column withCells:(NSArray*)cellArray +{ + int i; - // Save cell widths and heights in arrays - aFloat = [NSNumber numberWithFloat: cs.height]; - [row_heights addObject:aFloat]; - aFloat = [NSNumber numberWithFloat: cs.width]; - for (i = 0;i < ncols; ++i) - [col_widths addObject:aFloat]; + /* Grow the matrix if necessary */ + if (column > numCols) + [self renewRows:(numRows == 0 ? 1 : numRows) columns:column]; + else if (numRows == 0) { + numRows = 1; + [cells addObject:[NSMutableArray array]]; + } - e = [cellArray objectEnumerator]; - o = [e nextObject]; - while (o) - { - [a addObject: o]; - [o retain]; - o = [e nextObject]; - } + numCols++; + for (i = 0; i < numRows; i++) + [[cells objectAtIndex:i] + replaceObjectAtIndex:column withObject:[cellArray objectAtIndex:i]]; + insertColumn (selectedCells, column); + + if (mode == NSRadioModeMatrix && !allowsEmptySelection && !selectedCell) + [self selectCellAtRow:0 column:0]; +} + +- (void)insertRow:(int)row +{ + int i; + + /* Grow the matrix if necessary */ + if (row > numRows) + [self renewRows:row columns:(numCols == 0 ? 1 : numCols)]; + else if (numCols == 0) + numCols = 1; + + [cells insertObject:[NSMutableArray arrayWithCapacity:numCols] atIndex:row]; + + numRows++; + for (i = 0; i < numCols; i++) + [self makeCellAtRow:row column:i]; + + insertRow (selectedCells, row); + + if (mode == NSRadioModeMatrix && !allowsEmptySelection && !selectedCell) + [self selectCellAtRow:0 column:0]; +} + +- (void)insertRow:(int)row withCells:(NSArray*)cellArray +{ + /* Grow the matrix if necessary */ + if (row > numRows) + [self renewRows:row columns:(numCols == 0 ? 1 : numCols)]; + else if (numCols == 0) + numCols = 1; + + [cells insertObject:[cellArray subarrayWithRange:NSMakeRange(0, numCols)] + atIndex:row]; + + insertRow (selectedCells, row); + + numRows++; + + if (mode == NSRadioModeMatrix && !allowsEmptySelection && !selectedCell) + [self selectCellAtRow:0 column:0]; +} + +- (NSCell*)makeCellAtRow:(int)row + column:(int)column +{ + NSCell* aCell; + + if (cellPrototype) + aCell = [[cellPrototype copy] autorelease]; + else if (cellClass) + aCell = [[cellClass new] autorelease]; + else + aCell = [[NSActionCell new] autorelease]; + + [[cells objectAtIndex:row] insertObject:aCell atIndex:column]; + return aCell; } - (NSRect)cellFrameAtRow:(int)row column:(int)column { - NSRect r; - int i; + NSRect rect; - /* Initialize the size to all zeroes */ - r.origin.x = 0; - r.origin.y = 0; - r.size.width = 0; - r.size.height = 0; - -#if 0 - /* Validate arguments */ - if ((row >= num_rows) || (row < 0)) - { - return r; - } - - if ((column >= num_cols) || (column < 0)) - { - return r; - } + rect.origin.x = column * (cellSize.width + intercell.width); +#if HAS_FLIPPED_VIEWS + rect.origin.y = row * (cellSize.height + intercell.height); +#else + rect.origin.y = (numRows - row - 1) * (cellSize.height + intercell.height); #endif - - /* Compute the x origin */ - for (i=0; i 1) - { - for (i=0; icolumn; j--) - { - [currentRow replaceObjectAtIndex:j withObject: - [currentRow objectAtIndex:i-1]]; - } - [currentRow replaceObjectAtIndex:column withObject:newCell]; - } - } -} - -- (void)insertColumn:(int)column withCells:(NSArray *)cellArray -{ - NSCell *newCell; - int i, count; - - [self insertColumn:column]; - - if (cellArray != nil) - { - count = [cellArray count]; - } - else - { - count = 0; - } - - for (i=0; i 1) - { - aRow = [rows lastObject]; - - for (i=num_rows-1; i> row; i--) - { - [rows replaceObjectAtIndex:i withObject:[rows objectAtIndex:i-1]]; - } - [rows replaceObjectAtIndex:row withObject:aRow]; - } -} - -- (void)insertRow:(int)row withCells:(NSArray *)cellArray -{ - int i; - id e, o; - - // No array then forget the insert - if (!cellArray) - return; - - [self insertRow:row]; - - e = [cellArray objectEnumerator]; - o = [e nextObject]; - i = 0; - while (o) - { - [self putCell: o atRow: row column: i]; - o = [e nextObject]; - ++i; - } -} - -- (NSSize)intercellSpacing -{ - return inter_cell; -} - -- (NSCell *)makeCellAtRow:(int)row - column:(int)column -{ - id newCell; - - if ((row < num_rows) - && (row > -1) - && (column < num_cols) - && (column > -1)) - { - newCell = [[cell_class alloc] init]; - [[rows objectAtIndex:row] replaceObjectAtIndex:column - withObject:newCell]; - return newCell; - } - else - { - return nil; - } -} - -- (void)putCell:(NSCell *)newCell +- (void)putCell:(NSCell*)newCell atRow:(int)row column:(int)column { - NSMutableArray *aRow; - - if ((row > -1) - && (row < num_rows) - && (column > -1) - && (column < num_cols)) - { - aRow = (NSMutableArray *)[rows objectAtIndex:row]; - [aRow replaceObjectAtIndex:column withObject:newCell]; - } + [[cells objectAtIndex:row] replaceObjectAtIndex:column withObject:newCell]; + [self lockFocus]; + [newCell drawWithFrame:[self cellFrameAtRow:row column:column] inView:self]; + [[self window] flushWindow]; + [self unlockFocus]; } - (void)removeColumn:(int)column { - int i; - NSMutableArray *aRow; - - if ((column > -1) && (column < num_cols)) - { - for (i=0; i= numCols) + return; + + if (column == selectedColumn) + [self selectCellAtRow:0 column:0]; + + for (i = 0; i < numRows; i++) + [[cells objectAtIndex:i] removeObjectAtIndex:column]; + + removeColumn (selectedCells, column); + numCols--; } - (void)removeRow:(int)row { - if ((row > -1) && (row < num_rows)) - { - [rows removeObjectAtIndex:row]; - - [row_heights removeObjectAtIndex:row]; - num_rows--; - } -} + if (row >= numRows) + return; -- empty -{ - [rows removeAllObjects]; - [selected_cells removeAllObjects]; - num_rows = 0; - num_cols = 0; - return self; + if (row == selectedRow) + [self selectCellAtRow:0 column:0]; + + [cells removeObjectAtIndex:row]; + removeRow (selectedCells, row); + numRows--; } - (void)renewRows:(int)newRows columns:(int)newColumns -{} - -- (void)setCellSize:(NSSize)aSize { - NSNumber *aFloat; - id old; - int i; + int i, j; - for (i=0; i numCols) { + /* First check to see if the rows really have fewer cells than + newColumns. This may happen because the row arrays are not shrink + when a lower number of cells is given. */ + if (numRows && newColumns > [[cells objectAtIndex:0] count]) { + /* Add columns to the existing rows. Call makeCellAtRow:column: + to be consistent. */ + for (i = 0; i < numRows; i++) { + for (j = numCols; j < newColumns; j++) + [self makeCellAtRow:i column:j]; + } } + } + numCols = newColumns; - for (i=0; i numRows) { + for (i = numRows; i < newRows; i++) { + [cells addObject:[NSMutableArray arrayWithCapacity:numCols]]; + for (j = 0; j < numCols; j++) + [self makeCellAtRow:i column:j]; } + } + numRows = newRows; + + growMatrix (selectedCells, newRows, newColumns); } -- (void)setColumnWidth:(int)width at:(int)column; +- (void)setCellSize:(NSSize)size { - NSNumber *aFloat; - id old; - - if ((column > -1) && (column < num_cols)) - { - aFloat = [NSNumber numberWithFloat: width]; - old = [col_widths objectAtIndex:column]; - [col_widths replaceObjectAtIndex:column withObject: aFloat]; - [old release]; - } + cellSize = size; + [self sizeToCells]; } -- (void)setIntercellSpacing:(NSSize)aSize +- (void)setIntercellSpacing:(NSSize)size { - inter_cell = aSize; + intercell = size; + [self sizeToCells]; } - (void)sortUsingFunction:(int (*)(id element1, id element2, void *userData))comparator - context:(void *)context -{} + context:(void*)context +{ + NSMutableArray* sorted = [NSMutableArray arrayWithCapacity:numRows*numCols]; + NSMutableArray* row; + int i, j, index = 0; + + for (i = 0; i < numRows; i++) + [sorted addObjectsFromArray:[[cells objectAtIndex:i] + subarrayWithRange:NSMakeRange(0, numCols)]]; + + [sorted sortUsingFunction:comparator context:context]; + + for (i = 0; i < numRows; i++) { + row = [cells objectAtIndex:i]; + for (j = 0; j < numCols; j++) { + [row replaceObjectAtIndex:j withObject:[sorted objectAtIndex:index]]; + index++; + } + } +} - (void)sortUsingSelector:(SEL)comparator -{} - -- (int)numCols; { - return num_cols; + NSMutableArray* sorted = [NSMutableArray arrayWithCapacity:numRows*numCols]; + NSMutableArray* row; + int i, j, index = 0; + + for (i = 0; i < numRows; i++) + [sorted addObjectsFromArray:[[cells objectAtIndex:i] + subarrayWithRange:NSMakeRange(0, numCols)]]; + + [sorted sortUsingSelector:comparator]; + + for (i = 0; i < numRows; i++) { + row = [cells objectAtIndex:i]; + for (j = 0; j < numCols; j++) { + [row replaceObjectAtIndex:j withObject:[sorted objectAtIndex:index]]; + index++; + } + } } -- (int)numRows; -{ - return num_rows; -} - -// -// Finding Matrix Coordinates -// -/* - * The next function returns NO if the point is located inside - * the matrix but also in an intercell gap, which may or may - * not be the behavior God intended... - */ -- (BOOL)getRow:(int *)row - column:(int *)column +- (BOOL)getRow:(int*)row + column:(int*)column forPoint:(NSPoint)aPoint { - NSRect myFrame = [self bounds]; - NSRect cFrame; - id re, ce; - id aRow, aCol; - int i, j; + BOOL isBetweenCells, insideBounds; - /* Trivial rejection if the point is not in the Matrix's frame rect */ + insideBounds = [self _getRow:row column:column + forPoint:aPoint + above:NO right:NO + isBetweenCells:&isBetweenCells]; - if (![self mouse: aPoint inRect: myFrame]) - { - NSDebugLog(@"NSMatrix point %f %f not in rect %f %f %f %f\n", - aPoint.x, aPoint.y, myFrame.origin.x, myFrame.origin.y, - myFrame.size.width, myFrame.size.height); - return NO; - } - - /* Here an optimized algo could be used at the expense of clarity */ - - re = [rows objectEnumerator]; - aRow = [re nextObject]; - i = 0; - while (aRow) - { - ce = [aRow objectEnumerator]; - aCol = [ce nextObject]; - j = 0; - while (aCol) - { - cFrame = [self cellFrameAtRow:i column:j]; - - if ([self mouse: aPoint inRect: cFrame]) - { - *row = i; - *column = j; - return YES; - } - aCol = [ce nextObject]; - ++j; - } - aRow = [re nextObject]; - ++i; - } - return NO; + if (!insideBounds || isBetweenCells) + return NO; + else return YES; } -- (BOOL)getRow:(int *)row - column:(int *)column - ofCell:(NSCell *)aCell +- (BOOL)getRow:(int*)row + column:(int*)column + ofCell:(NSCell*)aCell { - id re, ce; - id aRow, aCol; int i, j; - re = [rows objectEnumerator]; - aRow = [re nextObject]; - i = 0; - while (aRow) - { - ce = [aRow objectEnumerator]; - aCol = [ce nextObject]; - j = 0; - while (aCol) - { - if ((NSCell *)[self cellAtRow:i column:j] == aCell) - { - *row = i; - *column = j; - return YES; - } - aCol = [ce nextObject]; - ++j; - } - aRow = [re nextObject]; - ++i; - } + for (i = 0; i < numRows; i++) { + NSMutableArray* row = [cells objectAtIndex:i]; + + for (j = 0; j < numCols; j++) + if ([row objectAtIndex:j] == aCell) + return YES; + } + return NO; } -// -// Modifying Individual Cells -// - (void)setState:(int)value atRow:(int)row column:(int)column { - NSMutableArray *aRow; - NSCell *aCell; + NSCell* aCell = [self cellAtRow:row column:column]; - if ((row > -1) - && (row < num_rows) - && (column > -1) - && (column < num_cols)) - { - aRow = (NSMutableArray *)[rows objectAtIndex:row]; - aCell = (NSCell *)[aRow objectAtIndex:column]; - [aCell setState:value]; + if (!aCell) + return; + + if (mode == NSRadioModeMatrix) { + if (value) { + ASSIGN(selectedCell, aCell); + selectedRow = row; + selectedColumn = column; + [selectedCell setState:1]; } + else if (allowsEmptySelection) + [self deselectSelectedCell]; + } + else + [aCell setState:value]; + + [self lockFocus]; + [aCell drawWithFrame:[self cellFrameAtRow:row column:column] inView:self]; + [[self window] flushWindow]; + [self unlockFocus]; } -// -// Selecting Cells -// - (void)deselectAllCells { - if (allows_empty_selection) - [selected_cells removeAllObjects]; + int i, j; + NSArray* row; + NSCell* aCell; + + /* There is a bug right now in NSView that doesn't allow a view to be + locked focus more than one time. Uncomment this when the bug is fixed! */ +// [self lockFocus]; + for (i = 0; i < numRows; i++) { + row = [cells objectAtIndex:i]; + for (j = 0; j < numCols; j++) + if (((tMatrix)selectedCells)->matrix[i][j]) { + NSRect theFrame = [self cellFrameAtRow:i column:j]; + + aCell = [row objectAtIndex:j]; + [aCell setState:0]; + [aCell highlight:NO withFrame:theFrame inView:self]; + [aCell drawWithFrame:theFrame inView:self]; + ((tMatrix)selectedCells)->matrix[i][j] = NO; + } + } + [[self window] flushWindow]; +// [self unlockFocus]; } - (void)deselectSelectedCell { - int cnt = [selected_cells count]; - - // Is anything even selected? - if (cnt > 0) - // Only empty array if empty selection is allowed - if ((cnt != 1) || (allows_empty_selection)) - [selected_cells removeLastObject]; + [selectedCell setState:0]; + selectedCell = nil; + selectedRow = -1; + selectedColumn = -1; } - (void)selectAll:(id)sender { - [selected_cells removeAllObjects]; - [selected_cells addObjectsFromArray:[self cells]]; + int i, j; + NSArray* row; + + /* Make the selected cell the cell at (0, 0) */ + ASSIGN(selectedCell, [self cellAtRow:0 column:0]); + selectedRow = 0; + selectedColumn = 0; + + for (i = 0; i < numRows; i++) { + row = [cells objectAtIndex:i]; + + for (j = 0; j < numCols; j++) { + [[row objectAtIndex:j] setState:1]; + ((tMatrix)selectedCells)->matrix[i][j] = YES; + } + } + + [self display]; } - (void)selectCellAtRow:(int)row column:(int)column { - int index; - id aCell = [self cellAtRow:row column:column]; - - NSDebugLog(@"NSMatrix select cell at %d %d\n", row, column); - if (aCell != nil) - { - // Add to selected cell list if not already - index = [selected_cells indexOfObject:aCell]; - if ((index < 0) || (index > [selected_cells count])) - { - [selected_cells addObject:aCell]; - } + NSCell* aCell = [self cellAtRow:row column:column]; + + if (mode == NSRadioModeMatrix) { + /* Don't allow loosing of selection if in radio mode and empty selection + not allowed. Otherwise deselect the selected cell. */ + if (!aCell && !allowsEmptySelection) + return; + else if (selectedCell) { + NSRect f = [self cellFrameAtRow:selectedRow column:selectedColumn]; + + [selectedCell setState:0]; + [self lockFocus]; + [selectedCell drawWithFrame:f inView:self]; + [self unlockFocus]; } + } + else if (!aCell) + return; + + ASSIGN(selectedCell, aCell); + selectedRow = row; + selectedColumn = column; + [selectedCell setState:1]; + + [self lockFocus]; + [aCell drawWithFrame:[self cellFrameAtRow:row column:column] inView:self]; + [self unlockFocus]; + [[self window] flushWindow]; } - (BOOL)selectCellWithTag:(int)anInt { - id aCell = [self cellWithTag:anInt]; - int index; - - if (cell != nil) - { - index = [selected_cells indexOfObject:aCell]; + NSMutableArray* row; + id aCell; + int i, j; - if ((index < 0) || (index > [selected_cells count])) - { - [selected_cells addObject:aCell]; - } + for (i = numRows - 1; i >= 0; i--) { + row = [cells objectAtIndex:i]; + for (j = numCols - 1; j >= 0; j --) { + aCell = [row objectAtIndex:j]; + if ([aCell tag] == anInt) { + [self selectCellAtRow:i column:j]; return YES; - } else { - return NO; + } } + } + + return NO; } -- (id)selectedCell +- (NSArray*)selectedCells { - if ([selected_cells count]) - return [selected_cells lastObject]; + NSMutableArray* array = [NSMutableArray array]; + int i, j; - return nil; -} + for (i = 0; i < numRows; i++) { + NSArray* row = [cells objectAtIndex:i]; -/* - * returns an array of the selected cells - */ -- (NSArray *)selectedCells -{ - return selected_cells; -} + for (j = 0; j < numCols; j++) + if (((tMatrix)selectedCells)->matrix[i][j]) + [array addObject:[row objectAtIndex:j]]; + } -- (int)selectedColumn -{ - int row, col; - id aCell; - - if ([selected_cells count]) - { - aCell = [selected_cells lastObject]; - - if ([self getRow: &row column: &col ofCell: aCell]) - return col; - } - - // Not found - return -1; -} - -- (int)selectedRow -{ - int row, col; - id aCell; - - if ([selected_cells count]) - { - aCell = [selected_cells lastObject]; - - if ([self getRow: &row column: &col ofCell: aCell]) - return row; - } - - // Not found - return -1; + return array; } - (void)setSelectionFrom:(int)startPos to:(int)endPos anchor:(int)anchorPos highlight:(BOOL)flag -{} +{ + MPoint anchor = POINT_FROM_INDEX(anchorPos); + MPoint last = POINT_FROM_INDEX(startPos); + MPoint current = POINT_FROM_INDEX(endPos); + + if (selectionByRect) + [self _selectRectUsingAnchor:anchor last:last current:current]; + else + [self _selectContinuousUsingAnchor:anchor last:last current:current]; + [self display]; +} -// -// Finding Cells -// - (id)cellAtRow:(int)row column:(int)column { - id aRow; + if (row < 0 || row >= numRows || column < 0 || column >= numCols) + return nil; - if ((row >= num_rows) || (row < 0)) - { - NSLog(@"NSMatrix cellAt:: invalid row (%d)\n", row); - return nil; - } - aRow = [rows objectAtIndex: row]; - - if ((column >= [aRow count]) || (column < 0)) - { - NSLog(@"NSMatrix cellAt:: invalid column (%d)\n", column); - return nil; - } - - return [(NSArray *)aRow objectAtIndex:column]; + return [[cells objectAtIndex:row] objectAtIndex:column]; } - (id)cellWithTag:(int)anInt { - id re, ce; - NSMutableArray *aRow; - NSCell *aCell; + NSMutableArray* row; + id aCell; + int i, j; - // Loop through the rows and columns and find the cell - re = [rows objectEnumerator]; - aRow = [re nextObject]; - while (aRow) - { - ce = [aRow objectEnumerator]; - aCell = (NSCell *)[ce nextObject]; - while (aCell) - { - if ([aCell tag] == anInt) - return aCell; - aCell = (NSCell *)[ce nextObject]; - } + for (i = numRows - 1; i >= 0; i--) { + row = [cells objectAtIndex:i]; + for (j = numCols - 1; j >= 0; j --) { + aCell = [row objectAtIndex:j]; + if ([aCell tag] == anInt) + return aCell; } + } + return nil; } -- (NSArray *)cells +- (NSArray*)cells { - NSMutableArray *cells; - int i; - - if ((num_cols < 1) || (num_rows < 1)) - { - return nil; - } - else - { - cells = [[NSMutableArray alloc] - initWithCapacity:(num_rows * num_cols)]; - - for (i=0; i 0) && (row < (num_rows-1) )) - { - newSize.height += inter_cell.height; - } - } - - for (col=0; col 0) && (col < (num_cols-1) )) - { - newSize.width += inter_cell.width; - } - } - -#if 1 - NSDebugLog(@"NSMatrix size: %4.0f %4.0f\n",newSize.width,newSize.height); -#endif - - [(NSView *)self setFrameSize:newSize]; -} - -- (void)resizeWithOldSuperviewSize:(NSSize)oldSize -{ - NSDebugLog(@"NSMatrix resize %f %f old %f %f\n", bounds.size.width, - bounds.size.height, oldSize.width, oldSize.height); -} - -// -// Scrolling -// -- (BOOL)isAutoscroll -{ - return autoscroll; + newSize.width = numCols * (cellSize.width + intercell.width) + - intercell.width; + newSize.height = numRows * (cellSize.height + intercell.height) + - intercell.height; + [self setFrameSize:newSize]; } - (void)scrollCellToVisibleAtRow:(int)row column:(int)column -{} +{ + [self scrollRectToVisible:[self cellFrameAtRow:row column:column]]; +} - (void)setAutoscroll:(BOOL)flag { @@ -1302,53 +981,78 @@ static Class NSMATRIX_DEFAULT_CELL_CLASS = nil; - (void)setScrollable:(BOOL)flag { - scrollable = flag; + int i, j; + + for (i = 0; i < numRows; i++) { + NSArray* row = [cells objectAtIndex:i]; + + for (j = 0; j < numCols; j++) + [[row objectAtIndex:j] setScrollable:flag]; + } + [cellPrototype setScrollable:flag]; } -// -// Displaying -// -- (void)display; +- (void)drawRect:(NSRect)rect { - id re, ce; - int row, col; - NSMutableArray *aRow; - id aCol; + int i, j; + int row1, col1; // The cell at the upper left corner + int row2, col2; // The cell at the lower right corner + NSRect intRect, upperLeftRect; + NSArray* row; - NSDebugLog(@"NSMatrix display %f %f %f %f\n", bounds.origin.x, - bounds.origin.y, bounds.size.width, bounds.size.height); + [self _getRow:&row1 column:&col1 +#if HAS_FLIPPED_VIEWS + forPoint:rect.origin +#else + forPoint:NSMakePoint (rect.origin.x, rect.origin.y + rect.size.height) +#endif + above:NO right:NO + isBetweenCells:NULL]; + [self _getRow:&row2 column:&col2 +#if HAS_FLIPPED_VIEWS + forPoint:NSMakePoint(rect.origin.x + rect.size.width, + rect.origin.y + rect.size.height) +#else + forPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y) +#endif + above:NO right:NO + isBetweenCells:NULL]; - re = [rows objectEnumerator]; - aRow = (NSMutableArray *)[re nextObject]; - row = 0; - while (aRow) - { - ce = [aRow objectEnumerator]; - aCol = [ce nextObject]; - col = 0; - while (aCol) - { - [self drawCellAtRow: row column: col]; - ++col; - aCol = [ce nextObject]; - } - ++row; - aRow = [re nextObject]; + if (row1 < 0) + row1 = 0; + if (col1 < 0) + col1 = 0; + +// NSLog (@"display cells between (%d, %d) and (%d, %d)", +// row1, col1, row2, col2); + + /* Draw the cells within the drawing rectangle. */ + intRect = upperLeftRect = [self cellFrameAtRow:row1 column:col1]; + for (i = row1; i <= row2; i++) { + row = [cells objectAtIndex:i]; + intRect.origin.x = upperLeftRect.origin.x; + + for (j = col1; j <= col2; j++) { + NSCell *aCell = [row objectAtIndex:j]; + [aCell drawWithFrame:intRect inView:self]; + intRect.origin.x += cellSize.width + intercell.width; } - NSDebugLog(@"End NSMatrix display\n"); +#if HAS_FLIPPED_VIEWS + intRect.origin.y += cellSize.height + intercell.height; +#else + intRect.origin.y -= cellSize.height + intercell.height; +#endif + } + [[self window] flushWindow]; } - (void)drawCellAtRow:(int)row column:(int)column { - NSMutableArray *aRow = [rows objectAtIndex: row]; - NSCell *aCell = [aRow objectAtIndex: column]; + NSCell *aCell = [self cellAtRow:row column:column]; + NSRect cellFrame = [self cellFrameAtRow:row column:column]; - NSDebugLog(@"NSMatrix draw cell %d %d %d %d\n", row, column, [rows count], - [aRow count]); - [aCell drawWithFrame: - [self cellFrameAtRow:row column:column] - inView:self]; + [aCell drawWithFrame:cellFrame inView:self]; } - (void)highlightCell:(BOOL)flag @@ -1358,250 +1062,316 @@ static Class NSMATRIX_DEFAULT_CELL_CLASS = nil; NSCell *aCell = [self cellAtRow:row column:column]; NSRect cellFrame; - if (aCell != nil) - { - cellFrame = [self cellFrameAtRow:row column:column]; - [aCell highlight:flag withFrame:cellFrame inView:self]; - } -} - -// -// Target and Action -// -- (SEL)doubleAction -{ - return double_action; -} - -- (void)setDoubleAction:(SEL)aSelector -{ - double_action = aSelector; -} - -- (SEL)errorAction -{ - return error_action; + if (aCell) { + cellFrame = [self cellFrameAtRow:row column:column]; + [aCell highlight:flag + withFrame:[self cellFrameAtRow:row column:column] + inView:self]; + } } - (BOOL)sendAction { - NSCell *aCell = [self selectedCell]; + SEL theAction; + id theTarget; - NSDebugLog(@"NSMatrix -sendAction\n"); - if (!aCell) return NO; - - if ([aCell isKindOfClass:[NSActionCell class]]) - { - NSDebugLog(@"NSMatrix sending action\n"); - [self sendAction: [aCell action] to: [aCell target]]; - return YES; - } - NSDebugLog(@"NSMatrix no action\n"); + if (![selectedCell isEnabled]) return NO; + + theAction = [selectedCell action]; + theTarget = [selectedCell target]; + + if (theAction) { + if (theTarget) + [selectedCell perform:theAction withObject:self]; + else + [target perform:theAction withObject:self]; + } + else + [target perform:action withObject:self]; + + return YES; } - (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag { - BOOL (*test)(id, SEL, id); - id row, columns, col; - id aCell; - BOOL result; + int i, j; - // If the object doesn't respond to selector then quit - if (![anObject respondsToSelector: aSelector]) - return; + if (flag) { + for (i = 0; i < numRows; i++) { + NSMutableArray* row = [cells objectAtIndex:i]; - // Obtain function pointer to selector - test = (BOOL (*)(id, SEL, id))[anObject methodForSelector: aSelector]; + for (j = 0; j < numCols; j++) + if (![anObject perform:aSelector + withObject:[row objectAtIndex:j]]) + return; + } + } + else { + for (i = 0; i < numRows; i++) { + BOOL* row = ((tMatrix)selectedCell)->matrix[i]; + NSMutableArray* cellRow = [cells objectAtIndex:i]; - // Enumerate through all the cells - row = [rows objectEnumerator]; - columns = [row nextObject]; - while (columns) - { - col = [columns objectEnumerator]; - aCell = [col nextObject]; - while (aCell) - { - // Call the method - result = test(anObject, aSelector, aCell); - - // If the result is NO - // and we shouldn't continue for all cells - // then quit - if ((!result) && (!flag)) - return; - - aCell = [col nextObject]; - } - columns = [row nextObject]; - } + for (j = 0; j < numCols; j++) + if (row[i]) + if (![anObject perform:aSelector + withObject:[cellRow objectAtIndex:j]]) + return; + } + } } - (void)sendDoubleAction { - NSCell *aCell = [self selectedCell]; + if (![selectedCell isEnabled]) + return; - NSDebugLog(@"NSMatrix -sendDoubleAction\n"); - if (!aCell) return; - - if (double_action) - { - NSDebugLog(@"NSMatrix sending double action\n"); - [self sendAction: double_action to: [aCell target]]; - } - else - NSDebugLog(@"NSMatrix no double action\n"); + if (doubleAction) + [target perform:doubleAction withObject:self]; + else + [self sendAction]; } -- (void)setErrorAction:(SEL)aSelector +- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent { - error_action = aSelector; + return mode == NSListModeMatrix ? NO : YES; } -// -// Handling Event and Action Messages -// -- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent +- (void)mouseDown:(NSEvent*)theEvent { - if (mode == NSListModeMatrix) - { - return NO; - } - return YES; -} + BOOL isBetweenCells, insideBounds; + int row, column; + unsigned eventMask = NSLeftMouseUpMask | NSLeftMouseDownMask + | NSMouseMovedMask | NSLeftMouseDraggedMask | NSPeriodicMask; + NSPoint lastLocation = [theEvent locationInWindow]; + NSEvent* lastEvent = nil; + BOOL done = NO; + NSRect rect; + id aCell, previousCell = nil; + NSRect previousCellRect; + MPoint anchor; -- (void)highlightTrackingMode:(NSEvent *)theEvent -{ - NSPoint location; - NSPoint point; - NSCell *aCell; - int aRow, aCol; - NSRect cellFrame; - NSApplication *theApp = [NSApplication sharedApplication]; - BOOL mouseUp, done; - NSEvent *e; - unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask - | NSMouseMovedMask; + mouseDownFlags = [theEvent modifierFlags]; + lastLocation = [self convertPoint:lastLocation fromView:nil]; + [NSEvent startPeriodicEventsAfterDelay:0.05 withPeriod:0.05]; + ASSIGN(lastEvent, theEvent); + [self lockFocus]; - // Capture mouse - [[self window] captureMouse: self]; + while (!done) { + BOOL shouldProceedEvent = NO; - mouseUp = NO; - done = NO; - e = theEvent; - while (!done) - { - location = [e locationInWindow]; - point = [self convertPoint: location fromView: nil]; + insideBounds = [self _getRow:&row + column:&column + forPoint:lastLocation + above:NO right:NO + isBetweenCells:&isBetweenCells]; + if (insideBounds && !isBetweenCells) { + aCell = [self cellAtRow:row column:column]; + rect = [self cellFrameAtRow:row column:column]; - // Find out what cell was clicked on - if ([self getRow:&aRow column:&aCol forPoint:point]) - { - NSDebugLog(@"NSMatrix found row/column from point\n"); - - aCell = [self cellAtRow:aRow column:aCol]; - if (!aCell) - { - // Yikes problem here - NSLog(@"NSMatrix no cell at %d %d\n", aRow, aCol); - mouseUp = NO; - done = YES; - continue; - } - - NSDebugLog(@"NSMatrix found cell\n"); - cellFrame = [self cellFrameAtRow: aRow column: aCol]; - - mouseUp = [aCell trackMouse: e inRect: cellFrame - ofView:self untilMouseUp:YES]; - e = [theApp currentEvent]; - } - - // If mouse went up then we are done - if ((mouseUp) || ([e type] == NSLeftMouseUp)) - done = YES; - else - { - NSDebugLog(@"NSMatrix process another event\n"); - e = [theApp nextEventMatchingMask:event_mask untilDate:nil - inMode:nil dequeue:YES]; - } - } - - - // Release mouse - [[self window] releaseMouse: self]; - - // If the mouse went up in the button - if (mouseUp) - { - NSDebugLog(@"NSMatrix the mouse went up in a button\n"); - - // Unhighlight the cell - [aCell highlight: NO withFrame: cellFrame - inView: self]; - - // Select the cell - [self selectCellAtRow: aRow column: aCol]; - - NSDebugLog(@"NSMatrix send action\n"); - // Send action - if ([theEvent clickCount] == 1) - [self sendAction]; - else - [self sendDoubleAction]; - } -} - -- (void)mouseDown:(NSEvent *)theEvent -{ - NSView *view = [[self window] contentView]; - NSPoint location = [theEvent locationInWindow]; - NSPoint point = [super_view convertPoint:location fromView:view]; - - NSDebugLog(@"NSMatrix mouseDown at point %f %f\n", point.x, point.y); - - // What mode are we in? - switch(mode) - { + switch (mode) { case NSTrackModeMatrix: - break; + ASSIGN(selectedCell, aCell); + selectedRow = row; + selectedColumn = column; + + [selectedCell trackMouse:lastEvent + inRect:rect + ofView:self + untilMouseUp:YES]; + done = YES; + break; case NSHighlightModeMatrix: - NSDebugLog(@"NSMatrix NSHighlightModeMatrix\n"); - [self highlightTrackingMode: theEvent]; + if (previousCell == aCell) break; + [previousCell highlight:NO withFrame:previousCellRect inView:self]; + ASSIGN(selectedCell, aCell); + selectedRow = row; + selectedColumn = column; + [selectedCell highlight:YES withFrame:rect inView:self]; + [[self window] flushWindow]; + break; + case NSRadioModeMatrix: + if (previousCell == aCell) break; - case NSListModeMatrix: + /* At the first click, deselect the selected cell */ + if (!previousCell) { + NSRect f = [self cellFrameAtRow:selectedRow column:selectedColumn]; + id aCell = selectedCell; + + [self deselectSelectedCell]; + [aCell drawWithFrame:f inView:self]; + } + else + [previousCell highlight:NO withFrame:previousCellRect inView:self]; + + ASSIGN(selectedCell, aCell); + selectedRow = row; + selectedColumn = column; + [selectedCell highlight:YES withFrame:rect inView:self]; + [[self window] flushWindow]; + break; + + case NSListModeMatrix: { + unsigned modifiers = [lastEvent modifierFlags]; + + if (previousCell == aCell) break; + + /* When the user first clicks on a cell we clear the existing + selection unless Alternate or Shift key modifiers have been + pressed. */ + if (!previousCell) { + if (!(modifiers & NSShiftKeyMask) && + !(modifiers & NSAlternateKeyMask)) + [self deselectAllCells]; + + if ((modifiers & NSAlternateKeyMask)) + /* Consider the selected cell as the anchor to allow extending + the selection to the current cell. */ + anchor = MakePoint (selectedColumn, selectedRow); + else { + anchor = MakePoint (column, row); + + ASSIGN(selectedCell, aCell); + selectedRow = row; + selectedColumn = column; + + [selectedCell setState:1]; + [selectedCell highlight:YES withFrame:rect inView:self]; + [selectedCell drawWithFrame:rect inView:self]; + ((tMatrix)selectedCells)->matrix[row][column] = YES; + [[self window] flushWindow]; + break; + } + } + + if (selectionByRect) + [self _selectRectUsingAnchor:anchor + last:MakePoint (selectedColumn, selectedRow) + current:MakePoint (column, row)]; + else + [self _selectContinuousUsingAnchor:anchor + last:MakePoint (selectedColumn, selectedRow) + current:MakePoint (column, row)]; + + ASSIGN(selectedCell, aCell); + selectedRow = row; + selectedColumn = column; + [[self window] flushWindow]; + break; } + } + + previousCell = aCell; + previousCellRect = rect; + [self scrollRectToVisible:rect]; + } + + if (done) + break; + + /* Get the next event */ + while (!shouldProceedEvent) { + theEvent = [NSApp nextEventMatchingMask:eventMask + untilDate:[NSDate distantFuture] + inMode:NSEventTrackingRunLoopMode + dequeue:YES]; + switch ([theEvent type]) { + case NSPeriodic: + shouldProceedEvent = YES; + break; + case NSLeftMouseUp: + done = YES; + shouldProceedEvent = YES; + ASSIGN(lastEvent, theEvent); + break; + default: + ASSIGN(lastEvent, theEvent); + continue; + } + } + lastLocation = [lastEvent locationInWindow]; + lastLocation = [self convertPoint:lastLocation fromView:nil]; + } + + /* Finalize the selection */ + switch (mode) { + case NSTrackModeMatrix: + case NSHighlightModeMatrix: + [selectedCell setState:![selectedCell state]]; + [selectedCell highlight:NO withFrame:rect inView:self]; + [selectedCell drawWithFrame:rect inView:self]; + break; + case NSRadioModeMatrix: + [selectedCell setState:1]; + [selectedCell highlight:NO withFrame:rect inView:self]; + [selectedCell drawWithFrame:rect inView:self]; + break; + case NSListModeMatrix: + break; + } + + if ([selectedCell target]) + [[selectedCell target] perform:[selectedCell action] withObject:self]; + else if (target) + [target perform:action withObject:self]; + + [[self window] flushWindow]; + [self unlockFocus]; + [NSEvent stopPeriodicEvents]; + [lastEvent release]; } -- (int)mouseDownFlags +- (BOOL)performKeyEquivalent:(NSEvent*)theEvent { - return 0; -} + int i, j; + NSMutableArray* row; + NSString* key = [theEvent charactersIgnoringModifiers]; + + for (i = 0; i < numRows; i++) { + row = [cells objectAtIndex:i]; + for (j = 0; j < numCols; j++) { + NSCell* aCell = [row objectAtIndex:j]; + + if ([aCell isEnabled] && [[aCell keyEquivalent] isEqual:key]) { + NSCell* oldSelectedCell = selectedCell; + + selectedCell = aCell; + [self highlightCell:YES atRow:i column:j]; + [aCell setState:![aCell state]]; + [self sendAction]; + [self highlightCell:NO atRow:i column:j]; + selectedCell = oldSelectedCell; + + return YES; + } + } + } -- (BOOL)performKeyEquivalent:(NSEvent *)theEvent -{ return NO; } -// -// Managing the Cursor -// - (void)resetCursorRects -{} +{ + int i, j; + + for (i = 0; i < numRows; i++) { + NSArray* row = [cells objectAtIndex:i]; + + for (j = 0; j < numCols; j++) { + NSCell* aCell = [row objectAtIndex:j]; + [aCell resetCursorRect:[self cellFrameAtRow:i column:j] inView:self]; + } + } +} -// -// NSCoding protocol -// - (void)encodeWithCoder:aCoder { [super encodeWithCoder:aCoder]; @@ -1614,4 +1384,602 @@ static Class NSMATRIX_DEFAULT_CELL_CLASS = nil; return self; } +- (void)setMode:(NSMatrixMode)aMode { mode = aMode; } +- (NSMatrixMode)mode { return mode; } +- (void)setCellClass:(Class)class { cellClass = class; } +- (Class)cellClass { return cellClass; } +- (void)setPrototype:(NSCell*)aCell { ASSIGN(cellPrototype, aCell) } +- (id)prototype { return cellPrototype; } +- (NSSize)cellSize { return cellSize; } +- (NSSize)intercellSpacing { return intercell; } +- (void)setBackgroundColor:(NSColor*)c { ASSIGN(backgroundColor, c) } +- (NSColor*)backgroundColor { return backgroundColor; } +- (void)setCellBackgroundColor:(NSColor*)c { ASSIGN(cellBackgroundColor, c) } +- (NSColor*)cellBackgroundColor { return cellBackgroundColor; } +- (void)setDelegate:(id)object { ASSIGN(delegate, object) } +- (id)delegate { return delegate; } +- (void)setTarget:anObject { ASSIGN(target, anObject) } +- (id)target { return target; } +- (void)setAction:(SEL)sel { action = sel; } +- (SEL)action { return action; } +- (void)setDoubleAction:(SEL)sel { doubleAction = sel; } +- (SEL)doubleAction { return doubleAction; } +- (void)setErrorAction:(SEL)sel { errorAction = sel; } +- (SEL)errorAction { return errorAction; } +- (void)setAllowsEmptySelection:(BOOL)f { allowsEmptySelection = f; } +- (BOOL)allowsEmptySelection { return allowsEmptySelection; } +- (void)setSelectionByRect:(BOOL)flag { selectionByRect = flag; } +- (BOOL)isSelectionByRect { return selectionByRect; } +- (void)setDrawsBackground:(BOOL)flag { drawsBackground = flag; } +- (BOOL)drawsBackground { return drawsBackground; } +- (void)setDrawsCellBackground:(BOOL)f { drawsCellBackground = f; } +- (BOOL)drawsCellBackground { return drawsCellBackground; } +- (void)setAutosizesCells:(BOOL)flag { autosizesCells = flag; } +- (BOOL)autosizesCells { return autosizesCells; } +- (BOOL)isAutoscroll { return autoscroll; } +- (int)numberOfRows { return numRows; } +- (int)numberOfColumns { return numCols; } +- (id)selectedCell { return selectedCell; } +- (int)selectedColumn { return selectedColumn; } +- (int)selectedRow { return selectedRow; } +- (int)mouseDownFlags { return mouseDownFlags; } + +#if HAS_FLIPPED_VIEWS +- (BOOL)isFlipped { return YES; } +#endif + +@end + + +@implementation NSMatrix (PrivateMethods) + +#define SET_POINTER_VALUE(pointer, value) \ + do { if (pointer) *pointer = value; } while (0) + +/* Returns by reference the row and column of cell that is above or below or + to the left or to the right of point. `point' is in the matrix coordinates. + Returns NO if the point is outside the bounds of matrix, YES otherwise. + + Note that the cell numbering is flipped relative to the coordinate system. + */ +- (BOOL)_getRow:(int*)row + column:(int*)column + forPoint:(NSPoint)point + above:(BOOL)aboveRequired + right:(BOOL)rightRequired + isBetweenCells:(BOOL*)isBetweenCells +{ + BOOL rowReady = NO, colReady = NO; + BOOL betweenRows = NO, betweenCols = NO; + NSRect theBounds = [self bounds]; + + SET_POINTER_VALUE(isBetweenCells, NO); + + /* First check the limit cases */ + if (point.x > theBounds.size.width) { + SET_POINTER_VALUE(column, numCols); + colReady = YES; + } + else if (point.x < 0) { + SET_POINTER_VALUE(column, 0); + colReady = YES; + } + + if (point.y > theBounds.size.height) { + SET_POINTER_VALUE(row, numRows); + rowReady = YES; + } + else if (point.y < 0) { + SET_POINTER_VALUE(row, 0); + rowReady = YES; + } + + if (rowReady && colReady) + return NO; + + if (!rowReady) { + int approxRow = point.y / (cellSize.height + intercell.height); + float approxRowsHeight = approxRow * (cellSize.height + intercell.height); + + /* Determine if the point is inside the cell */ + betweenRows = !(point.y > approxRowsHeight + && point.y <= approxRowsHeight + cellSize.height); + + /* If the point is between cells then adjust the computed row taking into + account the `aboveRequired' flag. */ + if (aboveRequired && betweenRows) + approxRow++; + +#if HAS_FLIPPED_VIEWS + SET_POINTER_VALUE(row, approxRow); +#else + SET_POINTER_VALUE(row, numRows - approxRow - 1); +#endif + if (*row < 0) { + *row = -1; + rowReady = YES; + } + else if (*row >= numRows) { + *row = numRows - 1; + rowReady = YES; + } + } + + if (!colReady) { + int approxCol = point.x / (cellSize.width + intercell.width); + float approxColsWidth = approxCol * (cellSize.width + intercell.width); + + /* Determine if the point is inside the cell */ + betweenCols = !(point.x > approxColsWidth + && point.x <= approxColsWidth + cellSize.width); + + /* If the point is between cells then adjust the computed column taking + into account the `rightRequired' flag. */ + if (rightRequired && betweenCols) + approxCol++; + + SET_POINTER_VALUE(column, approxCol); + if (*column < 0) { + *column = -1; + colReady = YES; + } + else if (*column >= numCols) { + *column = numCols - 1; + colReady = YES; + } + } + + /* If the point is outside the matrix bounds return NO */ + if (rowReady || colReady) + return NO; + + if (betweenRows || betweenCols) + SET_POINTER_VALUE(isBetweenCells, YES); + return YES; +} + +/* This method is used to select cells in the list mode with selection by rect + option enabled. `anchor' is the first point in the selection (the coordinates + of the cell first clicked). `last' is the last point up to which the anterior + selection has been made. `current' is the point to which we must extend the + selection. */ + +- (void)_selectRectUsingAnchor:(MPoint)anchor + last:(MPoint)last + current:(MPoint)current +{ + /* We use an imaginar coordinate system whose center is the `anchor' point. We + should determine in which quadrants are located the `last' and the `current' + points. Based on this we extend the selection to the rectangle determined + by `anchor' and `current' points. + + The algorithm uses two rectangles: one determined by `anchor' and + `current' that defines how the final selection rectangle will look, and + another one determined by `anchor' and `last' that defines the current + visible selection. + + The three points above determine 9 distinct zones depending on the + position of `last' and `current' relative to `anchor'. Each of these + zones have a different way of extending the selection from `last' to + `current'. + + Note the coordinate system is a flipped one not a usual geometric one + (the y coordinate increases downward). + */ + + int dxca = current.x - anchor.x; + int dyca = current.y - anchor.y; + int dxla = last.x - anchor.x; + int dyla = last.y - anchor.y; + int dxca_dxla, dyca_dyla; + int selectRectsNo = 0; + MRect selectRect[2]; + int unselectRectsNo = 0; + MRect unselectRect[2]; + int tmpx, tmpy; + int i; + + dxca_dxla = SIGN(dxca) / (SIGN(dxla) ? SIGN(dxla) : 1); + dyca_dyla = SIGN(dyca) / (SIGN(dyla) ? SIGN(dyla) : 1); + + if (dxca_dxla >= 0) { + if (dyca_dyla >= 0) { + /* `current' is in the lower right quadrant. */ + if (ABS(dxca) <= ABS(dxla)) { + if (ABS(dyca) <= ABS(dyla)) { + /* `current' is in zone I. */ + + NSDebugLog (@"zone I"); + + if (dxca != dxla) { + i = unselectRectsNo++; + tmpx = dxca > 0 ? current.x + 1 : current.x + SIGN(dxla); + unselectRect[i].x = MIN(tmpx, last.x); + unselectRect[i].y = MIN(anchor.y, current.y); + unselectRect[i].width = ABS(last.x - tmpx); + unselectRect[i].height = ABS(current.y - anchor.y); + } + + if (dyca != dyla) { + i = unselectRectsNo++; + tmpy = dyca > 0 ? current.y + 1 : current.y + SIGN(dyla); + unselectRect[i].x = MIN(anchor.x, last.x); + unselectRect[i].y = MIN(tmpy, last.y); + unselectRect[i].width = ABS(last.x - anchor.x); + unselectRect[i].height = ABS(last.y - tmpy); + } + } + else { + /* `current' is in zone F. */ + + NSDebugLog (@"zone F"); + + selectRectsNo = 1; + + tmpy = dyla >= 0 ? last.y + 1 : last.y - 1; + selectRect[0].x = MIN(anchor.x, current.x); + selectRect[0].y = MIN(tmpy, current.y); + selectRect[0].width = ABS(current.x - anchor.x); + selectRect[0].height = ABS(current.y - tmpy); + + if (dxca != dxla) { + unselectRectsNo = 1; + tmpx = dxca > 0 ? current.x + 1 : current.x + SIGN(dxla); + unselectRect[0].x = MIN(tmpx, last.x); + unselectRect[0].y = MIN(anchor.y, last.y); + unselectRect[0].width = ABS(last.x - tmpx); + unselectRect[0].height = ABS(last.y - anchor.y); + } + } + } + else { + if (ABS(dyca) <= ABS(dyla)) { + /* `current' is in zone H. */ + + NSDebugLog (@"zone H"); + selectRectsNo = 1; + + tmpx = dxla >= 0 ? last.x + 1 : last.x - 1; + selectRect[0].x = MIN(tmpx, current.x); + selectRect[0].y = MIN(anchor.y, current.y); + selectRect[0].width = ABS(current.x - tmpx); + selectRect[0].height = ABS(current.y - anchor.y); + + if (dyca != dyla) { + unselectRectsNo = 1; + + tmpy = dyca >= 0 ? current.y + 1 : current.y - 1; + unselectRect[0].x = MIN(anchor.x, last.x); + unselectRect[0].y = MIN(tmpy, last.y); + unselectRect[0].width = ABS(last.x - anchor.x); + unselectRect[0].height = ABS(last.y - tmpy); + } + } + else { + /* `current' is in zone G. */ + + NSDebugLog (@"zone G"); + selectRectsNo = 2; + + tmpx = dxla >= 0 ? last.x + 1 : last.x - 1; + selectRect[0].x = MIN(tmpx, current.x); + selectRect[0].y = MIN(anchor.y, last.y); + selectRect[0].width = ABS(current.x - tmpx); + selectRect[0].height = ABS(last.y - anchor.y); + + tmpy = dyla >= 0 ? last.y + 1 : last.y - 1; + selectRect[1].x = MIN(anchor.x, current.x); + selectRect[1].y = MIN(tmpy, current.y); + selectRect[1].width = ABS(current.x - anchor.x); + selectRect[1].height = ABS(current.y - tmpy); + } + } + } + else { + /* `current' is in the upper right quadrant */ + + if (ABS(dxca) <= ABS(dxla)) { + /* `current' is in zone B. */ + + NSDebugLog (@"zone B"); + + selectRectsNo = 1; + tmpy = dyca > 0 ? anchor.y + 1 : anchor.y - 1; + selectRect[0].x = MIN(anchor.x, current.x); + selectRect[0].y = MIN(current.y, tmpy); + selectRect[0].width = ABS(current.x - anchor.x); + selectRect[0].height = ABS(tmpy - current.y); + + if (dyla) { + unselectRectsNo = 1; + tmpy = dyca < 0 ? anchor.y + 1 : anchor.y + SIGN(dyla); + unselectRect[0].x = MIN(anchor.x, current.x); + unselectRect[0].y = MIN(tmpy, last.y); + unselectRect[0].width = ABS(last.x - anchor.x); + unselectRect[0].height = ABS(last.y - tmpy); + } + + if (dxla && dxca != dxla) { + i = unselectRectsNo++; + tmpx = dxca > 0 ? current.x + 1 : current.x + SIGN(dxla); + unselectRect[i].x = MIN(tmpx, last.x); + unselectRect[i].y = MIN(anchor.y, last.y); + unselectRect[i].width = ABS(last.x - tmpx); + unselectRect[i].height = ABS(last.y - anchor.y); + } + } + else { + /* `current' is in zone A. */ + + NSDebugLog (@"zone A"); + + if (dyca != dyla) { + i = selectRectsNo++; + tmpy = dyca < 0 ? anchor.y - 1 : anchor.y + 1; + selectRect[i].x = MIN(anchor.x, last.x); + selectRect[i].y = MIN(tmpy, current.y); + selectRect[i].width = ABS(last.x - anchor.x); + selectRect[i].height = ABS(current.y - tmpy); + } + + i = selectRectsNo++; + tmpx = dxca > 0 ? last.x + 1 : last.x - 1; + selectRect[i].x = MIN(tmpx, current.x); + selectRect[i].y = MIN(current.y, anchor.y); + selectRect[i].width = ABS(current.x - tmpx); + selectRect[i].height = ABS(anchor.y - current.y); + + if (dyla) { + unselectRectsNo = 1; + tmpy = dyca < 0 ? anchor.y + 1 : anchor.y - 1; + unselectRect[0].x = MIN(anchor.x, last.x); + unselectRect[0].y = MIN(tmpy, last.y); + unselectRect[0].width = ABS(last.x - anchor.x); + unselectRect[0].height = ABS(last.y - tmpy); + } + } + } + } + else { + if (dyca_dyla > 0) { + /* `current' is in the lower left quadrant */ + if (ABS(dyca) <= ABS(dyla)) { + /* `current' is in zone D. */ + + NSDebugLog (@"zone D"); + selectRectsNo = 1; + + tmpx = dxca < 0 ? anchor.x - 1 : anchor.x + 1; + selectRect[0].x = MIN(tmpx, current.x); + selectRect[0].y = MIN(anchor.y, current.y); + selectRect[0].width = ABS(current.x - tmpx); + selectRect[0].height = ABS(current.y - anchor.y); + + if (dxla) { + unselectRectsNo = 1; + tmpx = dxca < 0 ? anchor.x + 1 : anchor.x - 1; + unselectRect[0].x = MIN(tmpx, last.x); + unselectRect[0].y = MIN(anchor.y, current.y); + unselectRect[0].width = ABS(last.x - tmpx); + unselectRect[0].height = ABS(current.y - anchor.y); + } + + if (dyla && dyca != dyla) { + i = unselectRectsNo++; + tmpy = dyca > 0 ? current.y + 1 : current.y + SIGN(dyla); + unselectRect[i].x = MIN(anchor.x, last.x); + unselectRect[i].y = MIN(tmpy, last.y); + unselectRect[i].width = ABS(last.x - anchor.x); + unselectRect[i].height = ABS(last.y - tmpy); + } + } + else { + /* `current' is in zone E. */ + + NSDebugLog (@"zone E"); + + i = selectRectsNo++; + tmpx = dxca > 0 ? anchor.x + 1 : anchor.x - 1; + selectRect[i].x = MIN(tmpx, current.x); + selectRect[i].y = MIN(anchor.y, last.y); + selectRect[i].width = ABS(current.x - tmpx); + selectRect[i].height = ABS(last.y - anchor.y); + + i = selectRectsNo++; + tmpy = dyca > 0 ? last.y + 1 : last.y - 1; + selectRect[i].x = MIN(current.x, anchor.x); + selectRect[i].y = MIN(current.y, tmpy); + selectRect[i].width = ABS(anchor.x - current.x); + selectRect[i].height = ABS(tmpy - current.y); + + if (dxla) { + unselectRectsNo = 1; + tmpx = dxca > 0 ? anchor.x - 1 : anchor.x + 1; + unselectRect[0].x = MIN(tmpx, last.x); + unselectRect[0].y = MIN(anchor.y, last.y); + unselectRect[0].width = ABS(last.x - tmpx); + unselectRect[0].height = ABS(last.y - anchor.y); + } + } + } + else { + /* `current' is in zone C. */ + + NSDebugLog (@"zone C"); + selectRectsNo = 1; + + selectRect[0].x = MIN(current.x, anchor.x); + selectRect[0].y = MIN(current.y, anchor.y); + selectRect[0].width = ABS(anchor.x - current.x); + selectRect[0].height = ABS(anchor.y - current.y); + + if (dyca != dyla) { + unselectRectsNo = 1; + unselectRect[0].x = MIN(anchor.x, last.x); + unselectRect[0].y = MIN(anchor.y, last.y); + unselectRect[0].width = ABS(last.x - anchor.x); + unselectRect[0].height = ABS(last.y - anchor.y); + } + } + } + + /* In this point we know what are the rectangles that must be unselected and + those that must be selected. Iterate on them and do the work. First unselect + and only then do the cells selection. */ + for (i = 0; i < unselectRectsNo; i++) + [self _setState:0 inRect:unselectRect[i]]; + for (i = 0; i < selectRectsNo; i++) + [self _setState:1 inRect:selectRect[i]]; +} + +- (void)_setState:(int)state inRect:(MRect)matrixRect +{ + int i, j, rowNo, colNo; + NSArray* row; + NSCell* aCell; + NSRect rect, upperLeftRect; + BOOL highlight = state ? YES : NO; + int cellsCount = [cells count]; + int rowCount; + + rect = upperLeftRect = [self cellFrameAtRow:matrixRect.y column:matrixRect.x]; + + for (i = 0, rowNo = matrixRect.y; + i <= matrixRect.height && rowNo < cellsCount; + i++, rowNo++) { + row = [cells objectAtIndex:rowNo]; + rowCount = [row count]; + rect.origin.x = upperLeftRect.origin.x; + + for (j = 0, colNo = matrixRect.x; + j <= matrixRect.width && colNo < rowCount; + j++, colNo++) { + aCell = [row objectAtIndex:colNo]; + [aCell setState:state]; + [aCell highlight:highlight withFrame:rect inView:self]; + [aCell drawWithFrame:rect inView:self]; + ((tMatrix)selectedCells)->matrix[rowNo][colNo] = YES; + rect.origin.x += cellSize.width + intercell.width; + } + rect.origin.y -= cellSize.height + intercell.height; + } +} + + +/* This method is used to select and unselect the cells in the list mode with + selection by rect option disabled. This method has a far lower complexity than + the similar method used by list mode with selection by rect option. */ +- (void)_selectContinuousUsingAnchor:(MPoint)anchor + last:(MPoint)last + current:(MPoint)current +{ + /* The idea is to compare the points based on their linear index in matrix and + do the appropriate action. */ + + int anchorIndex = INDEX_FROM_POINT(anchor); + int lastIndex = INDEX_FROM_POINT(last); + int currentIndex = INDEX_FROM_POINT(current); + BOOL doSelect = NO; + MPoint selectPoint; + BOOL doUnselect = NO; + MPoint unselectPoint; + + int dca = currentIndex - anchorIndex; + int dla = lastIndex - anchorIndex; + int dca_dla = SIGN(dca) / (SIGN(dla) ? SIGN(dla) : 1); + + if (dca_dla >= 0) { + if (ABS(dca) >= ABS(dla)) { + doSelect = YES; + if (currentIndex > lastIndex) { + selectPoint.x = lastIndex; + selectPoint.y = currentIndex; + } + else { + selectPoint.x = currentIndex; + selectPoint.y = lastIndex; + } + } + else { + doUnselect = YES; + if (currentIndex < lastIndex) { + unselectPoint.x = currentIndex + 1; + unselectPoint.y = lastIndex; + } + else { + unselectPoint.x = lastIndex; + unselectPoint.y = currentIndex - 1; + } + } + } + else { + doSelect = YES; + if (anchorIndex < currentIndex) { + selectPoint.x = anchorIndex; + selectPoint.y = currentIndex; + } + else { + selectPoint.x = currentIndex; + selectPoint.y = anchorIndex; + } + + doUnselect = YES; + if (anchorIndex < lastIndex) { + unselectPoint.x = anchorIndex; + unselectPoint.y = lastIndex; + } + else { + unselectPoint.x = lastIndex; + unselectPoint.y = anchorIndex; + } + } + + if (doUnselect) + [self _setState:0 startIndex:unselectPoint.x endIndex:unselectPoint.y]; + if (doSelect) + [self _setState:1 startIndex:selectPoint.x endIndex:selectPoint.y]; +} + +- (void)_setState:(int)state startIndex:(int)start endIndex:(int)end +{ + int i, j, colLimit; + NSArray* row; + NSCell* aCell; + NSRect rect, upperLeftRect; + BOOL highlight = state ? YES : NO; + MPoint startPoint = POINT_FROM_INDEX(start); + MPoint endPoint = POINT_FROM_INDEX(end); + + rect = upperLeftRect = [self cellFrameAtRow:startPoint.y column:0]; + + for (i = startPoint.y; i <= endPoint.y; i++) { + row = [cells objectAtIndex:i]; + + if (i == startPoint.y) { + j = startPoint.x; + rect.origin.x = upperLeftRect.origin.x + + j * (cellSize.width + intercell.width); + } + else { + j = 0; + rect.origin.x = upperLeftRect.origin.x; + } + + if (i == endPoint.y) + colLimit = endPoint.x; + else + colLimit = numCols - 1; + + for (; j <= colLimit; j++) { + aCell = [row objectAtIndex:j]; + [aCell setState:state]; + [aCell highlight:highlight withFrame:rect inView:self]; + [aCell drawWithFrame:rect inView:self]; + ((tMatrix)selectedCells)->matrix[i][j] = YES; + rect.origin.x += cellSize.width + intercell.width; + } + rect.origin.y -= cellSize.height + intercell.height; + } +} + @end diff --git a/Source/NSScroller.m b/Source/NSScroller.m index ecf3e4a2f..38aa6d017 100644 --- a/Source/NSScroller.m +++ b/Source/NSScroller.m @@ -288,7 +288,7 @@ id gnustep_gui_nsscroller_class = nil; { last_point = point; e = [theApp nextEventMatchingMask:event_mask untilDate:nil - inMode:nil dequeue:YES]; + inMode:NSEventTrackingRunLoopMode dequeue:YES]; point = [self convertPoint: [e locationInWindow] fromView: nil]; if (is_horizontal) @@ -383,7 +383,7 @@ id gnustep_gui_nsscroller_class = nil; { last_point = point; e = [theApp nextEventMatchingMask:event_mask untilDate:nil - inMode:nil dequeue:YES]; + inMode:NSEventTrackingRunLoopMode dequeue:YES]; point = [self convertPoint: [e locationInWindow] fromView: nil]; diff --git a/Source/NSWindow.m b/Source/NSWindow.m index aa42b0733..aef10b52c 100644 --- a/Source/NSWindow.m +++ b/Source/NSWindow.m @@ -936,7 +936,7 @@ NSString *NSWindowWillMoveNotification = @"WindowWillMove"; { NSApplication *theApp = [NSApplication sharedApplication]; return [theApp nextEventMatchingMask: mask untilDate: nil - inMode: @"" dequeue: YES]; + inMode:NSEventTrackingRunLoopMode dequeue: YES]; } - (NSEvent *)nextEventMatchingMask:(unsigned int)mask diff --git a/aclocal.m4 b/aclocal.m4 index ffd32b7fa..c64ae4a13 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -2,7 +2,8 @@ # # Copyright (C) 1995, 1996 Free Software Foundation, Inc. # -# Written by: Adam Fedor +# Author: Adam Fedor +# Author: Ovidiu Predescu # # This file is part of the GNU Objective-C library. # @@ -145,3 +146,138 @@ AC_SUBST(DYNAMIC_BUNDLER_LINKER)dnl AC_SUBST(DYNAMIC_LDFLAGS)dnl AC_SUBST(DYNAMIC_CFLAGS)dnl ]) + +AC_DEFUN(AC_LANG_OBJECTIVE_C, +[AC_REQUIRE([AC_PROG_CC])dnl +define([AC_LANG], [AC_LANG_OBJECTIVE_C])dnl +ac_ext=m +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $OBJC_RUNTIME_FLAG' +ac_compile='${CC-cc} -c $OBJC_RUNTIME_FLAG $CFLAGS conftest.$ac_ext 1>&AC_FD_CC 2>&AC_FD_CC' +ac_link='${CC-cc} -o conftest $OBJC_RUNTIME_FLAG $CFLAGS $LDFLAGS conftest.$ac_ext $LIBS $OBJC_LIBS 1>&AC_FD_CC 2>&AC_FD_CC' +])dnl + +AC_DEFUN(AC_FIND_FOUNDATION, +[dnl +AC_SUBST(FOUNDATION_LIBRARY)dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_C_CROSS])dnl +AC_MSG_CHECKING(for the Foundation library) +AC_CACHE_VAL(ac_cv_foundation_library, +[AC_LANG_SAVE[]dnl +AC_LANG_OBJECTIVE_C[] +AC_TRY_COMPILE( +#include +, +, ac_cv_foundation_library="$ac_cv_foundation_library gnustep-base") +AC_TRY_COMPILE( +#include +, +, ac_cv_foundation_library="$ac_cv_foundation_library libFoundation") +AC_TRY_COMPILE( +#include +, +, ac_cv_foundation_library="$ac_cv_foundation_library libobjects") +AC_LANG_RESTORE[]dnl +if test "$FOUNDATION" = ""; then +AC_TRY_CPP( +#include +, ac_cv_foundation_library=foundation) +else + ac_cv_foundation_library=$FOUNDATION +fi +])dnl +libs_found=`echo ${ac_cv_foundation_library} | awk '{print NF}' -` +if test $libs_found -gt 1; then + echo "" 1>&2 + AC_MSG_ERROR([More than one Foundation library installed on your system. In the FOUNDATION variable you must specify exactly one of the following libraries: ${ac_cv_foundation_library}]) +fi +FOUNDATION_LIBRARY=`echo ${ac_cv_foundation_library} | awk '{print $1}'` +case "$FOUNDATION_LIBRARY" in + foundation) + OBJC_RUNTIME=next + + # save the prefix + old_prefix=$prefix + prefix=$ac_default_prefix + CFLAGS="-I`eval \"echo $includedir\"`/next $CFLAGS" + # restore the value of prefix + prefix=$old_prefix + + LIBS="$LIBS -lFoundation_s"; + AC_DEFINE(NeXT_foundation_LIBRARY);; + libobjects) + LIBS="$LIBS -lobjects" + AC_DEFINE(GNUSTEP_BASE_LIBRARY);; + gnustep-base) + LIBS="$LIBS -lgnustep-base" + AC_DEFINE(GNUSTEP_BASE_LIBRARY);; + libFoundation) + if test "$FOUNDATION_LIB" = ""; then + FOUNDATION_LIB=Foundation + fi + LIBS="-l${FOUNDATION_LIB} $LIBS" + AC_DEFINE(LIB_FOUNDATION_LIBRARY);; + *) + AC_MSG_ERROR(Unknown $FOUNDATION_LIBRARY library!);; +esac +AC_MSG_RESULT(${ac_cv_foundation_library}) +AC_DETERMINE_FOUNDATION_RUNTIME +])dnl + +AC_DEFUN(AC_DETERMINE_FOUNDATION_RUNTIME, +[dnl +AC_SUBST(OBJC_RUNTIME)dnl +AC_SUBST(OBJC_RUNTIME_FLAG)dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_C_CROSS])dnl +AC_MSG_CHECKING(for the Objective-C runtime) +AC_CACHE_VAL(ac_cv_objc_runtime, +[if test "$OBJC_RUNTIME" = ""; then + AC_LANG_SAVE[]dnl + AC_LANG_OBJECTIVE_C[] + AC_TRY_LINK([#include ], + [extern id objc_lookUpClass(char*); + id class = objc_lookUpClass("NSObject"); + id obj = [class alloc]; + puts([[obj description] cString]); + ], ac_cv_objc_runtime=NeXT, ac_cv_objc_runtime=unknown) + if test $ac_cv_objc_runtime = unknown; then + OBJC_RUNTIME_FLAG=-fgnu-runtime + LIBS="$LIBS -lobjc" + AC_TRY_LINK([#include + #include ], + [id class = objc_lookup_class("NSObject"); + id obj = [class alloc]; + puts([[obj description] cString]); + ], ac_cv_objc_runtime=GNU, ac_cv_objc_runtime=unknown) + fi + AC_LANG_RESTORE[] +fi +])dnl +OBJC_RUNTIME=$ac_cv_objc_runtime +if test "`echo ${OBJC_RUNTIME} | tr a-z A-Z`" = "GNU"; then + OBJC_RUNTIME=GNU + OBJC_RUNTIME_FLAG=-fgnu-runtime + ac_cv_objc_runtime=GNU + LIBS="$LIBS -lobjc" + AC_DEFINE(GNU_RUNTIME) +elif test "`echo ${OBJC_RUNTIME} | tr a-z A-Z`" = "NEXT"; then + OBJC_RUNTIME=NeXT + OBJC_RUNTIME_FLAG=-fnext-runtime + ac_cv_objc_runtime=NeXT + AC_DEFINE(NeXT_RUNTIME) +else + OBJC_RUNTIME=unknown +fi +if test ${OBJC_RUNTIME} = unknown; then + echo + rm -f conftest* confdefs* core core.* *.core + AC_MSG_ERROR([Cannot determine the Objective-C runtime! Probably you have +to specify some additional libraries needed to link an ObjC program, so please +take a look in the config.log file to see the reason and try again.]) +fi +AC_MSG_RESULT(${ac_cv_objc_runtime}) +])dnl diff --git a/configure b/configure index 56f62e63f..d1455163b 100755 --- a/configure +++ b/configure @@ -1098,6 +1098,373 @@ fi config_include='' +# Checking for some additional libraries we might need +echo $ac_n "checking for -ldl""... $ac_c" 1>&6 +ac_lib_var=`echo dl'_'dlopen | tr './+\055' '__p_'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo dl | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi + +echo $ac_n "checking for -lpthread""... $ac_c" 1>&6 +ac_lib_var=`echo pthread'_'pthread_create | tr './+\055' '__p_'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lpthread $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo pthread | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi + +echo $ac_n "checking for -lm""... $ac_c" 1>&6 +ac_lib_var=`echo m'_'sqrt | tr './+\055' '__p_'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lm $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo m | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi + + +# Determine the Foundation library +echo $ac_n "checking for the Foundation library""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_foundation_library'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_ext=m +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $OBJC_RUNTIME_FLAG' +ac_compile='${CC-cc} -c $OBJC_RUNTIME_FLAG $CFLAGS conftest.$ac_ext 1>&5 2>&5' +ac_link='${CC-cc} -o conftest $OBJC_RUNTIME_FLAG $CFLAGS $LDFLAGS conftest.$ac_ext $LIBS $OBJC_LIBS 1>&5 2>&5' + +cat > conftest.$ac_ext < + +int main() { return 0; } +int t() { + +; return 0; } +EOF +if { (eval echo configure:1257: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_foundation_library="$ac_cv_foundation_library gnustep-base" +fi +rm -f conftest* + +cat > conftest.$ac_ext < + +int main() { return 0; } +int t() { + +; return 0; } +EOF +if { (eval echo configure:1273: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_foundation_library="$ac_cv_foundation_library libFoundation" +fi +rm -f conftest* + +cat > conftest.$ac_ext < + +int main() { return 0; } +int t() { + +; return 0; } +EOF +if { (eval echo configure:1289: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_foundation_library="$ac_cv_foundation_library libobjects" +fi +rm -f conftest* + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +if test "$FOUNDATION" = ""; then +cat > conftest.$ac_ext < + +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1308: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_foundation_library=foundation +else + echo "$ac_err" >&5 +fi +rm -f conftest* +else + ac_cv_foundation_library=$FOUNDATION +fi + +fi +libs_found=`echo ${ac_cv_foundation_library} | awk '{print NF}' -` +if test $libs_found -gt 1; then + echo "" 1>&2 + { echo "configure: error: More than one Foundation library installed on your system. In the FOUNDATION variable you must specify exactly one of the following libraries: ${ac_cv_foundation_library}" 1>&2; exit 1; } +fi +FOUNDATION_LIBRARY=`echo ${ac_cv_foundation_library} | awk '{print }'` +case "$FOUNDATION_LIBRARY" in + foundation) + OBJC_RUNTIME=next + + # save the prefix + old_prefix=$prefix + prefix=$ac_default_prefix + CFLAGS="-I`eval \"echo $includedir\"`/next $CFLAGS" + # restore the value of prefix + prefix=$old_prefix + + LIBS="$LIBS -lFoundation_s"; + cat >> confdefs.h <<\EOF +#define NeXT_foundation_LIBRARY 1 +EOF +;; + libobjects) + LIBS="$LIBS -lobjects" + cat >> confdefs.h <<\EOF +#define GNUSTEP_BASE_LIBRARY 1 +EOF +;; + gnustep-base) + LIBS="$LIBS -lgnustep-base" + cat >> confdefs.h <<\EOF +#define GNUSTEP_BASE_LIBRARY 1 +EOF +;; + libFoundation) + if test "$FOUNDATION_LIB" = ""; then + FOUNDATION_LIB=Foundation + fi + LIBS="-l${FOUNDATION_LIB} $LIBS" + cat >> confdefs.h <<\EOF +#define LIB_FOUNDATION_LIBRARY 1 +EOF +;; + *) + { echo "configure: error: Unknown $FOUNDATION_LIBRARY library!" 1>&2; exit 1; };; +esac +echo "$ac_t""${ac_cv_foundation_library}" 1>&6 +echo $ac_n "checking for the Objective-C runtime""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_objc_runtime'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$OBJC_RUNTIME" = ""; then + ac_ext=m +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $OBJC_RUNTIME_FLAG' +ac_compile='${CC-cc} -c $OBJC_RUNTIME_FLAG $CFLAGS conftest.$ac_ext 1>&5 2>&5' +ac_link='${CC-cc} -o conftest $OBJC_RUNTIME_FLAG $CFLAGS $LDFLAGS conftest.$ac_ext $LIBS $OBJC_LIBS 1>&5 2>&5' + + cat > conftest.$ac_ext < +int main() { return 0; } +int t() { +extern id objc_lookUpClass(char*); + id class = objc_lookUpClass("NSObject"); + id obj = [class alloc]; + puts([[obj description] cString]); + +; return 0; } +EOF +if { (eval echo configure:1393: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + ac_cv_objc_runtime=NeXT +else + rm -rf conftest* + ac_cv_objc_runtime=unknown +fi +rm -f conftest* + + if test $ac_cv_objc_runtime = unknown; then + OBJC_RUNTIME_FLAG=-fgnu-runtime + LIBS="$LIBS -lobjc" + cat > conftest.$ac_ext < + #include +int main() { return 0; } +int t() { +id class = objc_lookup_class("NSObject"); + id obj = [class alloc]; + puts([[obj description] cString]); + +; return 0; } +EOF +if { (eval echo configure:1418: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + ac_cv_objc_runtime=GNU +else + rm -rf conftest* + ac_cv_objc_runtime=unknown +fi +rm -f conftest* + + fi + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' + +fi + +fi +OBJC_RUNTIME=$ac_cv_objc_runtime +if test "`echo ${OBJC_RUNTIME} | tr a-z A-Z`" = "GNU"; then + OBJC_RUNTIME=GNU + OBJC_RUNTIME_FLAG=-fgnu-runtime + ac_cv_objc_runtime=GNU + LIBS="$LIBS -lobjc" + cat >> confdefs.h <<\EOF +#define GNU_RUNTIME 1 +EOF + +elif test "`echo ${OBJC_RUNTIME} | tr a-z A-Z`" = "NEXT"; then + OBJC_RUNTIME=NeXT + OBJC_RUNTIME_FLAG=-fnext-runtime + ac_cv_objc_runtime=NeXT + cat >> confdefs.h <<\EOF +#define NeXT_RUNTIME 1 +EOF + +else + OBJC_RUNTIME=unknown +fi +if test ${OBJC_RUNTIME} = unknown; then + echo + rm -f conftest* confdefs* core core.* *.core + { echo "configure: error: Cannot determine the Objective-C runtime! Probably you have +to specify some additional libraries needed to link an ObjC program, so please +take a look in the config.log file to see the reason and try again." 1>&2; exit 1; } +fi +echo "$ac_t""${ac_cv_objc_runtime}" 1>&6 + + + #-------------------------------------------------------------------- # Write the Makefiles and configuration files #-------------------------------------------------------------------- @@ -1225,6 +1592,9 @@ s%@INSTALL_DATA@%$INSTALL_DATA%g s%@RANLIB@%$RANLIB%g s%@LN_S@%$LN_S%g s%@config_include@%$config_include%g +s%@FOUNDATION_LIBRARY@%$FOUNDATION_LIBRARY%g +s%@OBJC_RUNTIME@%$OBJC_RUNTIME%g +s%@OBJC_RUNTIME_FLAG@%$OBJC_RUNTIME_FLAG%g CEOF EOF diff --git a/configure.in b/configure.in index 4adddae71..242fa4e3d 100644 --- a/configure.in +++ b/configure.in @@ -91,6 +91,14 @@ fi config_include='' AC_SUBST(config_include) +# Checking for some additional libraries we might need +AC_CHECK_LIB(dl, dlopen) +AC_CHECK_LIB(pthread, pthread_create) +AC_CHECK_LIB(m, sqrt) + +# Determine the Foundation library +AC_FIND_FOUNDATION + #-------------------------------------------------------------------- # Write the Makefiles and configuration files #--------------------------------------------------------------------