mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-06-01 21:01:56 +00:00
Rewrite key view handling
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@14805 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
ec4279d10a
commit
82d40abd70
5 changed files with 388 additions and 114 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2002-10-21 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/NSView.m: Key view code ... complete rewrite to match
|
||||||
|
MacOS-X implementation.
|
||||||
|
|
||||||
Mon Oct 21 01:17:41 2002 Nicola Pero <n.pero@mi.flashnet.it>
|
Mon Oct 21 01:17:41 2002 Nicola Pero <n.pero@mi.flashnet.it>
|
||||||
|
|
||||||
* Source/NSView.m ([-setNextKeyView:], [-setPreviousKeyView:]):
|
* Source/NSView.m ([-setNextKeyView:], [-setPreviousKeyView:]):
|
||||||
|
@ -9,6 +14,8 @@ Mon Oct 21 01:17:41 2002 Nicola Pero <n.pero@mi.flashnet.it>
|
||||||
|
|
||||||
* Headers/gnustep/gui/NSComboBox.h: Add APPKIT_EXPORT and make layout
|
* Headers/gnustep/gui/NSComboBox.h: Add APPKIT_EXPORT and make layout
|
||||||
a bit more consistent.
|
a bit more consistent.
|
||||||
|
* Source/NSTextView.m: ([-dealloc]) remove unneeded RETAIN()
|
||||||
|
Fixes for beugs reported by Caba Conti.
|
||||||
|
|
||||||
2002-10-18 Adam Fedor <fedor@gnu.org>
|
2002-10-18 Adam Fedor <fedor@gnu.org>
|
||||||
|
|
||||||
|
|
|
@ -106,8 +106,8 @@ enum {
|
||||||
BOOL _allocate_gstate;
|
BOOL _allocate_gstate;
|
||||||
BOOL _renew_gstate;
|
BOOL _renew_gstate;
|
||||||
|
|
||||||
NSView *_nextKeyView;
|
void *_nextKeyView;
|
||||||
NSView *_previousKeyView;
|
void *_previousKeyView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -69,8 +69,9 @@
|
||||||
_next_responder = aResponder;
|
_next_responder = aResponder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Determining the first responder
|
* Returns YES if the receiver is able to become the first responder,
|
||||||
|
* NO otherwise.
|
||||||
*/
|
*/
|
||||||
- (BOOL) acceptsFirstResponder
|
- (BOOL) acceptsFirstResponder
|
||||||
{
|
{
|
||||||
|
|
|
@ -352,19 +352,15 @@ static NSNotificationCenter *nc;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void) dealloc
|
||||||
{
|
{
|
||||||
if (_tvf.owns_text_network == YES)
|
if (_tvf.owns_text_network == YES)
|
||||||
{
|
{
|
||||||
if (_textStorage != nil)
|
if (_textStorage != nil)
|
||||||
{
|
{
|
||||||
/* Balance the RELEASE we sent to us to break the retain cycle
|
/* This releases all the text objects (us included) which means
|
||||||
in initWithFrame: or initWithCoder: (otherwise releasing the
|
* this method will be called again ... so this time we just return.
|
||||||
_textStorage will make our retain count go below zero ;-) */
|
*/
|
||||||
RETAIN (self);
|
|
||||||
|
|
||||||
/* This releases all the text objects (us included) in
|
|
||||||
* fall. */
|
|
||||||
DESTROY (_textStorage);
|
DESTROY (_textStorage);
|
||||||
|
|
||||||
/* When the rest of the text network is released, we'll be
|
/* When the rest of the text network is released, we'll be
|
||||||
|
|
474
Source/NSView.m
474
Source/NSView.m
|
@ -68,6 +68,21 @@
|
||||||
#include <AppKit/NSWorkspace.h>
|
#include <AppKit/NSWorkspace.h>
|
||||||
#include <AppKit/PSOperators.h>
|
#include <AppKit/PSOperators.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need a fast array that can store objects without retain/release ...
|
||||||
|
*/
|
||||||
|
#define GSI_ARRAY_TYPES GSUNION_OBJ
|
||||||
|
#define GSI_ARRAY_NO_RELEASE 1
|
||||||
|
#define GSI_ARRAY_NO_RETAIN 1
|
||||||
|
|
||||||
|
#ifdef GSIArray
|
||||||
|
#undef GSIArray
|
||||||
|
#endif
|
||||||
|
#include <base/GSIArray.h>
|
||||||
|
|
||||||
|
#define nKV(O) ((GSIArray)(O->_nextKeyView))
|
||||||
|
#define pKV(O) ((GSIArray)(O->_previousKeyView))
|
||||||
|
|
||||||
/* Variable tells this view and subviews that we're printing. Not really
|
/* Variable tells this view and subviews that we're printing. Not really
|
||||||
a class variable because we want it visible to subviews also
|
a class variable because we want it visible to subviews also
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +106,7 @@ struct NSWindow_struct
|
||||||
hierarchy of NSViews, headed by the window's content view. Every
|
hierarchy of NSViews, headed by the window's content view. Every
|
||||||
other view in a window is a descendant of this view.</p>
|
other view in a window is a descendant of this view.</p>
|
||||||
|
|
||||||
<p>Subclasses can override <code>drawRect:</code> in order to
|
<p>Subclasses can override -drawRect: in order to
|
||||||
implement their appearance. Other methods of NSView and NSResponder
|
implement their appearance. Other methods of NSView and NSResponder
|
||||||
can also be overridden to handle user generated events.</p>
|
can also be overridden to handle user generated events.</p>
|
||||||
|
|
||||||
|
@ -280,18 +295,106 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
|
|
||||||
- (void) dealloc
|
- (void) dealloc
|
||||||
{
|
{
|
||||||
|
NSView *tmp;
|
||||||
|
unsigned count;
|
||||||
|
|
||||||
while ([_sub_views count] > 0)
|
while ([_sub_views count] > 0)
|
||||||
{
|
{
|
||||||
[[_sub_views lastObject] removeFromSuperviewWithoutNeedingDisplay];
|
[[_sub_views lastObject] removeFromSuperviewWithoutNeedingDisplay];
|
||||||
}
|
}
|
||||||
if (_nextKeyView != nil)
|
|
||||||
|
/*
|
||||||
|
* Remove self from view chain. Try to mimic MacOS-X behavior ...
|
||||||
|
* We send setNextKeyView: messages to all view for which we are the
|
||||||
|
* next key view, setting their next key view to nil.
|
||||||
|
*
|
||||||
|
* First we do the obvious stuff using the standard methods.
|
||||||
|
*/
|
||||||
|
[self setNextKeyView: nil];
|
||||||
|
[[self previousKeyView] setNextKeyView: nil];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now, we locate any remaining cases where a view has us as its next
|
||||||
|
* view, and ask the view to change that.
|
||||||
|
*/
|
||||||
|
if (pKV(self) != 0)
|
||||||
{
|
{
|
||||||
[_nextKeyView setPreviousKeyView: nil];
|
count = GSIArrayCount(pKV(self));
|
||||||
|
while (count-- > 0)
|
||||||
|
{
|
||||||
|
tmp = GSIArrayItemAtIndex(pKV(self), count).obj;
|
||||||
|
if ([tmp nextKeyView] == self)
|
||||||
|
{
|
||||||
|
[tmp setNextKeyView: nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (_previousKeyView != nil)
|
|
||||||
|
/*
|
||||||
|
* Now we clean up the previous view array, in case subclasses have
|
||||||
|
* overridden the default -setNextkeyView: method and broken things.
|
||||||
|
* We also relase the memory we used.
|
||||||
|
*/
|
||||||
|
if (pKV(self) != 0)
|
||||||
{
|
{
|
||||||
[_previousKeyView setNextKeyView: nil];
|
count = GSIArrayCount(pKV(self));
|
||||||
|
while (count-- > 0)
|
||||||
|
{
|
||||||
|
tmp = GSIArrayItemAtIndex(pKV(self), count).obj;
|
||||||
|
if (tmp != nil && nKV(tmp) != 0)
|
||||||
|
{
|
||||||
|
unsigned otherCount = GSIArrayCount(nKV(tmp));
|
||||||
|
|
||||||
|
while (otherCount-- > 1)
|
||||||
|
{
|
||||||
|
if (GSIArrayItemAtIndex(nKV(tmp), otherCount).obj == self)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex(nKV(tmp), otherCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GSIArrayItemAtIndex(nKV(tmp), 0).obj == self)
|
||||||
|
{
|
||||||
|
GSIArraySetItemAtIndex(nKV(tmp), (GSIArrayItem)nil, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GSIArrayClear(pKV(self));
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), pKV(self));
|
||||||
|
pKV(self) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we clean up all views which have us as their previous view.
|
||||||
|
* We also relase the memory we used.
|
||||||
|
*/
|
||||||
|
if (nKV(self) != 0)
|
||||||
|
{
|
||||||
|
count = GSIArrayCount(nKV(self));
|
||||||
|
while (count-- > 0)
|
||||||
|
{
|
||||||
|
tmp = GSIArrayItemAtIndex(nKV(self), count).obj;
|
||||||
|
if (tmp != nil && pKV(tmp) != 0)
|
||||||
|
{
|
||||||
|
unsigned otherCount = GSIArrayCount(pKV(tmp));
|
||||||
|
|
||||||
|
while (otherCount-- > 1)
|
||||||
|
{
|
||||||
|
if (GSIArrayItemAtIndex(pKV(tmp), otherCount).obj == self)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex(pKV(tmp), otherCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GSIArrayItemAtIndex(pKV(tmp), 0).obj == self)
|
||||||
|
{
|
||||||
|
GSIArraySetItemAtIndex(pKV(tmp), (GSIArrayItem)nil, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GSIArrayClear(nKV(self));
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), nKV(self));
|
||||||
|
nKV(self) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
RELEASE(_matrixToWindow);
|
RELEASE(_matrixToWindow);
|
||||||
RELEASE(_matrixFromWindow);
|
RELEASE(_matrixFromWindow);
|
||||||
RELEASE(_frameMatrix);
|
RELEASE(_frameMatrix);
|
||||||
|
@ -305,7 +408,9 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Adds <var>aView</var> as a subview of the receiver. */
|
/**
|
||||||
|
* Adds aView as a subview of the receiver.
|
||||||
|
*/
|
||||||
- (void) addSubview: (NSView*)aView
|
- (void) addSubview: (NSView*)aView
|
||||||
{
|
{
|
||||||
if (aView == nil)
|
if (aView == nil)
|
||||||
|
@ -316,7 +421,7 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
if ([self isDescendantOf: aView])
|
if ([self isDescendantOf: aView])
|
||||||
{
|
{
|
||||||
[NSException raise: NSInvalidArgumentException
|
[NSException raise: NSInvalidArgumentException
|
||||||
format: @"addSubview: creates a loop in the views tree!\n"];
|
format: @"addSubview: creates a loop in the views tree!"];
|
||||||
}
|
}
|
||||||
|
|
||||||
RETAIN(aView);
|
RETAIN(aView);
|
||||||
|
@ -352,7 +457,8 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
if ([self isDescendantOf: aView])
|
if ([self isDescendantOf: aView])
|
||||||
{
|
{
|
||||||
[NSException raise: NSInvalidArgumentException
|
[NSException raise: NSInvalidArgumentException
|
||||||
format: @"addSubview: positioned: relativeTo: creates a loop in the views tree!\n"];
|
format: @"addSubview:positioned:relativeTo: creates a "
|
||||||
|
@"loop in the views tree!"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aView == otherView)
|
if (aView == otherView)
|
||||||
|
@ -389,11 +495,10 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns <code>self</code> if <var>aView</var> is the receiver or
|
* Returns self if aView is the receiver or aView is a subview of the receiver,
|
||||||
<var>aView</var> is a subview of the receiver, the ancestor view
|
* the ancestor view shared by aView and the receiver if any, or
|
||||||
shared by <var>aView</var> and the receiver, if any,
|
* aView if it is an ancestor of the receiver, otherwise returns nil.
|
||||||
<var>aView</var> if it is an ancestor of the receiver, otherwise
|
*/
|
||||||
returns <code>nil</code>. */
|
|
||||||
- (NSView*) ancestorSharedWithView: (NSView*)aView
|
- (NSView*) ancestorSharedWithView: (NSView*)aView
|
||||||
{
|
{
|
||||||
if (self == aView)
|
if (self == aView)
|
||||||
|
@ -420,8 +525,8 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns <code>YES</code> if <var>aView</var> is an ancestor of the receiver.
|
* Returns YES if aView is an ancestor of the receiver.
|
||||||
*/
|
*/
|
||||||
- (BOOL) isDescendantOf: (NSView*)aView
|
- (BOOL) isDescendantOf: (NSView*)aView
|
||||||
{
|
{
|
||||||
if (aView == self)
|
if (aView == self)
|
||||||
|
@ -454,8 +559,9 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Removes the receiver from its superviews list of subviews, by
|
* Removes the receiver from its superviews list of subviews, by
|
||||||
invoking the superviews [-removeSubview:] method. */
|
* invoking the superviews [-removeSubview:] method.
|
||||||
|
*/
|
||||||
- (void) removeFromSuperviewWithoutNeedingDisplay
|
- (void) removeFromSuperviewWithoutNeedingDisplay
|
||||||
{
|
{
|
||||||
if (_super_view != nil)
|
if (_super_view != nil)
|
||||||
|
@ -526,8 +632,8 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Removes <var>oldView</var> from the receiver and places
|
* Removes oldView from the receiver and places newView in its place.
|
||||||
<var>newView</var> in its place. */
|
*/
|
||||||
- (void) replaceSubview: (NSView*)oldView with: (NSView*)newView
|
- (void) replaceSubview: (NSView*)oldView with: (NSView*)newView
|
||||||
{
|
{
|
||||||
if (newView == oldView)
|
if (newView == oldView)
|
||||||
|
@ -616,18 +722,18 @@ GSSetDragTypes(NSView* obj, NSArray *types)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Notifies the receiver that its superview is being changed to
|
* Notifies the receiver that its superview is being changed to newSuper.
|
||||||
<var>newSuperview</var>. */
|
*/
|
||||||
- (void) viewWillMoveToSuperview: (NSView*)newSuper
|
- (void) viewWillMoveToSuperview: (NSView*)newSuper
|
||||||
{
|
{
|
||||||
_super_view = newSuper;
|
_super_view = newSuper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Notifies the receiver that it will now be a view of <var>newWindow</var>.
|
* Notifies the receiver that it will now be a view of newWindow.
|
||||||
Note, this method is also used when removing a view from a window
|
* Note, this method is also used when removing a view from a window
|
||||||
(in which case, <var>newWindow</var> is nil) to let all the subviews know
|
* (in which case, newWindow is nil ) to let all the subviews know
|
||||||
that they have also been removed from the window.
|
* that they have also been removed from the window.
|
||||||
*/
|
*/
|
||||||
- (void) viewWillMoveToWindow: (NSWindow*)newWindow
|
- (void) viewWillMoveToWindow: (NSWindow*)newWindow
|
||||||
{
|
{
|
||||||
|
@ -2307,18 +2413,21 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
|
||||||
/*
|
/*
|
||||||
* Aiding Event Handling
|
* Aiding Event Handling
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns <code>YES</code> if the view object will accept the first
|
* Returns YES if the view object will accept the first
|
||||||
click received when in an inactive window, and <code>NO</code>
|
* click received when in an inactive window, and NO
|
||||||
otherwise. */
|
* otherwise.
|
||||||
|
*/
|
||||||
- (BOOL) acceptsFirstMouse: (NSEvent*)theEvent
|
- (BOOL) acceptsFirstMouse: (NSEvent*)theEvent
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the subview, lowest in the receiver's hierarchy, which
|
* Returns the subview, lowest in the receiver's hierarchy, which
|
||||||
contains <var>aPoint</var> */
|
* contains aPoint, or nil if there is no such view.
|
||||||
|
*/
|
||||||
- (NSView*) hitTest: (NSPoint)aPoint
|
- (NSView*) hitTest: (NSPoint)aPoint
|
||||||
{
|
{
|
||||||
NSPoint p;
|
NSPoint p;
|
||||||
|
@ -2359,8 +2468,8 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns whether or not <var>aPoint</var> lies within <var>aRect</var>
|
* Returns whether or not aPoint lies within aRect.
|
||||||
*/
|
*/
|
||||||
- (BOOL) mouse: (NSPoint)aPoint inRect: (NSRect)aRect
|
- (BOOL) mouse: (NSPoint)aPoint inRect: (NSRect)aRect
|
||||||
{
|
{
|
||||||
return NSMouseInRect (aPoint, aRect, _rFlags.flipped_view);
|
return NSMouseInRect (aPoint, aRect, _rFlags.flipped_view);
|
||||||
|
@ -2446,114 +2555,274 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) setNextKeyView: (NSView *)aView
|
|
||||||
{
|
|
||||||
/* As an exception, we do not retain aView, to avoid retain loops
|
|
||||||
* (the simplest being a view retaining and being retained by
|
|
||||||
* another view), which prevents objects from being ever
|
|
||||||
* deallocated. To understand how we manage without retaining
|
|
||||||
* _nextKeyView, see [NSView -dealloc]. */
|
|
||||||
|
|
||||||
/* A safety measure against recursion. */
|
/**
|
||||||
if (aView == _nextKeyView)
|
* <p>The effect of the -setNextkeyView: method is to set aView to be the
|
||||||
|
* value returned by subsequent calls to the receivers -nextKeyView method.
|
||||||
|
* This also has the effect of setting the previous key view of aView,
|
||||||
|
* so that subsequent calls to its -previousKeyView method will return
|
||||||
|
* the receiver.
|
||||||
|
* </p>
|
||||||
|
* <p>As a special case, if you pass nil as aView then the -previousKeyView
|
||||||
|
* of the receivers current -nextKeyView is set to nil as well as the
|
||||||
|
* receivers -nextKeyView: being set to nil.<br />
|
||||||
|
* This behavior provides MacOS-X compatibility.
|
||||||
|
* </p>
|
||||||
|
* <p>If you pass a non-view object other than nil, an
|
||||||
|
* NSInternaInconsistencyException is raised.
|
||||||
|
* </p>
|
||||||
|
* <p><strong>NB</strong> This method does <em>NOT</em> cause aView to be
|
||||||
|
* retained, and if aView is deallocated, the [NSView-dealloc] method will
|
||||||
|
* automatically remove it from the key view chain it is in.
|
||||||
|
* </p>
|
||||||
|
* <p>For keyboard navigation, views are linked together in a chain, so that
|
||||||
|
* the current first responder view can be changed by stepping backward
|
||||||
|
* and forward in that chain. This is the method for building and modifying
|
||||||
|
* that chain.
|
||||||
|
* </p>
|
||||||
|
* <p>The MacOS-X documentation refers to this chain as a <em>loop</em>, but
|
||||||
|
* the actual implementation is not a loop at all (except as a special case
|
||||||
|
* when you make the chain into a loop). In fact, while each view may have
|
||||||
|
* only zero or one <em>next</em> view, and zero or one <em>previous</em>
|
||||||
|
* view, several views may have their <em>next</em> view set to a single
|
||||||
|
* view and/or their <em>previous</em> views set to a single view. So the
|
||||||
|
* actual setup is a directed graph rather than a loop.
|
||||||
|
* </p>
|
||||||
|
* <p>While a directed graph is a very powerful and flexible way of managing
|
||||||
|
* the way views get keyboard focus in response to tabs etc, it can be
|
||||||
|
* confusing if misused. It is probably best therefore, to set your views
|
||||||
|
* up as a single loop within each window.
|
||||||
|
* </p>
|
||||||
|
* <example>
|
||||||
|
* [a setNextKeyView: b];
|
||||||
|
* [b setNextKeyView: c];
|
||||||
|
* [c setNextKeyView: d];
|
||||||
|
* [d setNextKeyView: a];
|
||||||
|
* </example>
|
||||||
|
*/
|
||||||
|
- (voidi) setNextKeyView: (NSView *)aView
|
||||||
|
{
|
||||||
|
NSView *tmp;
|
||||||
|
unsigned count;
|
||||||
|
|
||||||
|
if (aView != nil && [aView isKindOfClass: viewClass] == NO)
|
||||||
{
|
{
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"[NSView -setNextKeyView:] passed non-view object %@", aView];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aView == nil)
|
||||||
|
{
|
||||||
|
if (nKV(self) != 0)
|
||||||
|
{
|
||||||
|
tmp = GSIArrayItemAtIndex(nKV(self), 0).obj;
|
||||||
|
if (tmp != nil)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Remove all reference to self from our next key view.
|
||||||
|
*/
|
||||||
|
if (pKV(tmp) != 0)
|
||||||
|
{
|
||||||
|
count = GSIArrayCount(pKV(tmp));
|
||||||
|
while (count-- > 1)
|
||||||
|
{
|
||||||
|
if (GSIArrayItemAtIndex(pKV(tmp), count).obj == self)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex(pKV(tmp), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GSIArrayItemAtIndex(pKV(tmp), 0).obj == self)
|
||||||
|
{
|
||||||
|
GSIArraySetItemAtIndex(pKV(tmp), (GSIArrayItem)nil, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Clear link to the next key view.
|
||||||
|
*/
|
||||||
|
GSIArraySetItemAtIndex(nKV(self), (GSIArrayItem)nil, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aView == nil || [aView isKindOfClass: viewClass])
|
if (nKV(self) == 0)
|
||||||
{
|
{
|
||||||
if (_nextKeyView != nil)
|
/*
|
||||||
{
|
* Create array and ensure that it has a nil item at index 0 ...
|
||||||
NSView *oldNextKeyView = _nextKeyView;
|
* so we always have room for the pointer to the next view.
|
||||||
|
*/
|
||||||
/* Discard the pointer to us in the old next key view. To
|
nKV(self) = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSIArray_t));
|
||||||
* prevent [oldNextKeyView setPreviousKeyView: nil] from
|
GSIArrayInitWithZoneAndCapacity(nKV(self), NSDefaultMallocZone(), 1);
|
||||||
* calling us recursively, set _nextKeyView to nil for
|
GSIArrayAddItem(nKV(self), (GSIArrayItem)nil);
|
||||||
* the time of the call. */
|
}
|
||||||
_nextKeyView = nil;
|
else
|
||||||
|
{
|
||||||
if ([oldNextKeyView previousKeyView] != nil)
|
/* A safety measure against recursion. */
|
||||||
{
|
tmp = GSIArrayItemAtIndex(nKV(self), 0).obj;
|
||||||
[oldNextKeyView setPreviousKeyView: nil];
|
if (tmp == aView)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Assign the _nextKeyView first to prevent recursion. */
|
|
||||||
_nextKeyView = aView;
|
|
||||||
|
|
||||||
if (aView != nil)
|
|
||||||
{
|
{
|
||||||
if ([aView previousKeyView] != self)
|
return;
|
||||||
{
|
|
||||||
[aView setPreviousKeyView: self];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pKV(aView) == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Create array and ensure that it has a nil item at index 0 ...
|
||||||
|
* so we always have room for the pointer to the previous view.
|
||||||
|
*/
|
||||||
|
pKV(aView) = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GSIArray_t));
|
||||||
|
GSIArrayInitWithZoneAndCapacity(pKV(aView), NSDefaultMallocZone(), 1);
|
||||||
|
GSIArrayAddItem(pKV(aView), (GSIArrayItem)nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell the old previous view of aView that aView no longer points to it.
|
||||||
|
*/
|
||||||
|
tmp = GSIArrayItemAtIndex(pKV(aView), 0).obj;
|
||||||
|
if (tmp != nil)
|
||||||
|
{
|
||||||
|
count = GSIArrayCount(nKV(tmp));
|
||||||
|
while (count-- > 1)
|
||||||
|
{
|
||||||
|
if (GSIArrayItemAtIndex(nKV(tmp), count).obj == aView)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex(nKV(tmp), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If the view still points to aView, make a note of it in the
|
||||||
|
* 'previous' array of aView while making space for the new link.
|
||||||
|
*/
|
||||||
|
if (GSIArrayItemAtIndex(nKV(tmp), 0).obj == aView)
|
||||||
|
{
|
||||||
|
GSIArrayInsertItem(pKV(aView), (GSIArrayItem)nil, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up 'previous' link in aView to point to us.
|
||||||
|
*/
|
||||||
|
GSIArraySetItemAtIndex(pKV(aView), (GSIArrayItem)self, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell our current 'next' view that we are no longer pointing to it.
|
||||||
|
*/
|
||||||
|
tmp = GSIArrayItemAtIndex(nKV(self), 0).obj;
|
||||||
|
if (tmp != nil)
|
||||||
|
{
|
||||||
|
count = GSIArrayCount(pKV(tmp));
|
||||||
|
while (count-- > 1)
|
||||||
|
{
|
||||||
|
if (GSIArrayItemAtIndex(pKV(tmp), count).obj == self)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex(pKV(tmp), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If the view still points to us, make a note of it in the
|
||||||
|
* 'next' array while making space for the new link to aView.
|
||||||
|
*/
|
||||||
|
if (GSIArrayItemAtIndex(pKV(tmp), 0).obj == self)
|
||||||
|
{
|
||||||
|
GSIArrayInsertItem(nKV(self), (GSIArrayItem)nil, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up 'next' link to point to aView.
|
||||||
|
*/
|
||||||
|
GSIArraySetItemAtIndex(nKV(self), (GSIArrayItem)aView, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next view after the receiver in the key view chain.<br />
|
||||||
|
* Returns nil if there is no view after the receiver.<br />
|
||||||
|
* The next view is set up using the -setNextKeyView: method.<br />
|
||||||
|
* The key view chain is used to determine the order in which views become
|
||||||
|
* first responder when using keyboard navigation.
|
||||||
|
*/
|
||||||
- (NSView *) nextKeyView
|
- (NSView *) nextKeyView
|
||||||
{
|
{
|
||||||
return _nextKeyView;
|
if (nKV(self) == 0)
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return GSIArrayItemAtIndex(nKV(self), 0).obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first available view after the receiver which is
|
||||||
|
* actually able to become first responder. See -nextKeyView and
|
||||||
|
* [NSResponder-acceptsFirstResponder]
|
||||||
|
*/
|
||||||
- (NSView *) nextValidKeyView
|
- (NSView *) nextValidKeyView
|
||||||
{
|
{
|
||||||
NSView *theView;
|
NSView *theView;
|
||||||
|
|
||||||
theView = _nextKeyView;
|
theView = [self nextKeyView];
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if ([theView acceptsFirstResponder] || (theView == nil)
|
if ([theView acceptsFirstResponder] || (theView == nil)
|
||||||
|| (theView == self))
|
|| (theView == self))
|
||||||
return theView;
|
{
|
||||||
|
return theView;
|
||||||
|
}
|
||||||
theView = [theView nextKeyView];
|
theView = [theView nextKeyView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GNUstep addition ... a conveninece method to insert a view in the
|
||||||
|
* key view chain before the receiver, using the -previousKeyView and
|
||||||
|
* -setNextKeyView: methods.
|
||||||
|
*/
|
||||||
- (void) setPreviousKeyView: (NSView *)aView
|
- (void) setPreviousKeyView: (NSView *)aView
|
||||||
{
|
{
|
||||||
if (aView == _previousKeyView)
|
NSView *p = [self previousKeyView];
|
||||||
|
|
||||||
|
if (aView == p || aView == self)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
[p setNextKeyView: aView];
|
||||||
if (aView == nil || [aView isKindOfClass: viewClass])
|
[aView setNextKeyView: self];
|
||||||
{
|
|
||||||
if (_previousKeyView != nil)
|
|
||||||
{
|
|
||||||
NSView *oldPreviousKeyView = _previousKeyView;
|
|
||||||
|
|
||||||
_previousKeyView = nil;
|
|
||||||
if ([oldPreviousKeyView nextKeyView] != nil)
|
|
||||||
{
|
|
||||||
[oldPreviousKeyView setNextKeyView: nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_previousKeyView = aView;
|
|
||||||
|
|
||||||
if (aView != nil)
|
|
||||||
{
|
|
||||||
if ([aView nextKeyView] != self)
|
|
||||||
{
|
|
||||||
[aView setNextKeyView: self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the view before the receiver in the key view chain.<br />
|
||||||
|
* Returns nil if there is no view before the receiver in the chain.<br />
|
||||||
|
* The previous view of the receiver was set up by passing it as the
|
||||||
|
* argument to a call of -setNextKeyView: on that view.<br />
|
||||||
|
* The key view chain is used to determine the order in which views become
|
||||||
|
* first responder when using keyboard navigation.
|
||||||
|
*/
|
||||||
- (NSView *) previousKeyView
|
- (NSView *) previousKeyView
|
||||||
{
|
{
|
||||||
return _previousKeyView;
|
if (pKV(self) == 0)
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return GSIArrayItemAtIndex(pKV(self), 0).obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first available view before the receiver which is
|
||||||
|
* actually able to become first responder. See -nextKeyView and
|
||||||
|
* [NSResponder-acceptsFirstResponder]
|
||||||
|
*/
|
||||||
- (NSView *) previousValidKeyView
|
- (NSView *) previousValidKeyView
|
||||||
{
|
{
|
||||||
NSView *theView;
|
NSView *theView;
|
||||||
|
|
||||||
theView = _previousKeyView;
|
theView = [self previousKeyView];
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if ([theView acceptsFirstResponder] || (theView == nil)
|
if ([theView acceptsFirstResponder] || (theView == nil)
|
||||||
|| (theView == self))
|
|| (theView == self))
|
||||||
return theView;
|
{
|
||||||
|
return theView;
|
||||||
|
}
|
||||||
theView = [theView previousKeyView];
|
theView = [theView previousKeyView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3278,7 +3547,8 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
|
||||||
at: &_is_rotated_or_scaled_from_base];
|
at: &_is_rotated_or_scaled_from_base];
|
||||||
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_post_frame_changes];
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_post_frame_changes];
|
||||||
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autoresizes_subviews];
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autoresizes_subviews];
|
||||||
[aDecoder decodeValueOfObjCType: @encode(unsigned int) at: &_autoresizingMask];
|
[aDecoder decodeValueOfObjCType: @encode(unsigned int)
|
||||||
|
at: &_autoresizingMask];
|
||||||
_nextKeyView = [aDecoder decodeObject];
|
_nextKeyView = [aDecoder decodeObject];
|
||||||
_previousKeyView = [aDecoder decodeObject];
|
_previousKeyView = [aDecoder decodeObject];
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue