IUmplement tool tip help

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@23732 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2006-10-02 19:22:22 +00:00
parent 2c011d4cb4
commit ab9ac7d741
7 changed files with 684 additions and 7 deletions

View file

@ -1,3 +1,13 @@
2006-10-02 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GNUmakefile: Add GSToolTips.[hm]
* Source/NSWindow.m: Add private tooltip functionality.
* Source/GSToolTips.h: Interface to let views and windows handle tips.
* Source/GSToolTips.m: ToolTip implementation ... main part.
* Source/NSView.m: Use GSToolTips to implement tool tips.
* Headers/AppKit/NSResponder.h: Add a flag for views with tool tips.
Basic implementation of tool tip help.
2006-10-02 Nicola Pero <nicola.pero@meta-innovation.com>
* configure.ac: Check the new variable GNUSTEP_IS_FLATTENED,

View file

@ -77,6 +77,7 @@
/* change to keep track of it. */
unsigned valid_rects:1; /* Some cursor rects may be ok. */
unsigned needs_display:1; /* Window/view needs display. */
unsigned has_tooltips:1; /* The view has tooltips set. */
} _rFlags;
}

View file

@ -193,6 +193,7 @@ GSHorizontalTypesetter.m \
GSNibTemplates.m \
GSNibCompatibility.m \
GSTitleView.m \
GSToolTips.m \
GSToolbar.m \
GSToolbarView.m \
GSStandardWindowDecorationView.m \

103
Source/GSToolTips.h Normal file
View file

@ -0,0 +1,103 @@
/**
Interface of the GSToolTips class
Copyright (C) 2006 Free Software Foundation, Inc.
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: 2006
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <Foundation/NSObject.h>
#include "GNUstepGUI/GSTrackingRect.h"
@class NSTimer;
@class NSView;
@class NSWindow;
@interface GSToolTips : NSObject
{
NSView *view;
NSTrackingRectTag toolTipTag;
NSTimer *timer;
NSWindow *window;
BOOL restoreMouseMoved;
}
/** Destroy object handling tips for aView.
*/
+ (void) removeTipsForView: (NSView*)aView;
/** Return object to handle tips for aView.
*/
+ (GSToolTips*) tipsForView: (NSView*)aView;
/** <init/> Initialiser for internal use only.
*/
- (id) initForView: (NSView*)aView;
/** Support [NSView-addToolTipRect:owner:userData:].
*/
- (NSToolTipTag) addToolTipRect: (NSRect)aRect
owner: (id)anObject
userData: (void *)data;
/** Return the number of tooltip rectangles active.
*/
- (unsigned) count;
/** Handle mouse entry to tracking rect
*/
- (void) mouseEntered: (NSEvent *)theEvent;
/** Handle mouse exit from tracking rect
*/
- (void) mouseExited: (NSEvent *)theEvent;
/** Cancel tooltip because user clicked mouse.
*/
- (void) mouseDown: (NSEvent *)theEvent;
/** Move tooltip window with user's mouse movement.
*/
- (void) mouseMoved: (NSEvent *)theEvent;
/** Rebuild rectangles. Called by NSView whenever it has to rebuild its
* coordinate system because it has been resized, moved, or reparented.
*/
- (void) rebuild;
/** Support [NSView-removeAllToolTips]
*/
- (void) removeAllToolTips;
/** Support [NSView-removeToolTip:].
*/
- (void) removeToolTip: (NSToolTipTag)tag;
/** Support [NSView-setToolTip:].
*/
- (void) setToolTip: (NSString *)string;
/** Support [NSView-toolTip].
*/
- (NSString *) toolTip;
@end

494
Source/GSToolTips.m Normal file
View file

@ -0,0 +1,494 @@
/**
Implementation of the GSToolTips class
Copyright (C) 2006 Free Software Foundation, Inc.
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: 2006
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <Foundation/Foundation.h>
#include "AppKit/NSAttributedString.h"
#include "AppKit/NSBezierPath.h"
#include "AppKit/NSView.h"
#include "AppKit/NSWindow.h"
#include "GNUstepGUI/GSTrackingRect.h"
#include "GSToolTips.h"
@interface NSWindow (GNUstepPrivate)
+ (void) _setToolTipVisible: (GSToolTips*)t;
+ (GSToolTips*) _toolTipVisible;
@end
@interface NSObject (ToolTips)
- (NSString*) view: (NSView*)v stringForToolTip: (NSToolTipTag)t
point: (NSPoint)p userData: (void*)d;
@end
/* A trivial class to hold information about the provider of the tooltip
* string. Instance allocation/deallocation is managed by GSToolTip and
* are instances are stored in the user data field of tracking rectangles.
*/
@interface GSTTProvider : NSObject
{
id object;
void *data;
}
- (void*) data;
- (id) initWithObject: (id)o userData: (void*)d;
- (id) object;
- (void) setObject: (id)o;
@end
@implementation GSTTProvider
- (void*) data
{
return data;
}
- (id) initWithObject: (id)o userData: (void*)d
{
data = d;
object = o;
return self;
}
- (id) object
{
return object;
}
- (void) setObject: (id)o
{
object = o;
}
@end
@interface GSToolTips (Private)
- (void) _drawText: (NSAttributedString *)text;
- (void) _endDisplay;
- (void) _timedOut: (NSTimer *)timer;
@end
typedef struct NSView_struct
{
@defs(NSView)
} *NSViewPtr;
@implementation GSToolTips
static NSMapTable *viewsMap = 0;
+ (void) initialize
{
viewsMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSObjectMapValueCallBacks, 8);
}
+ (void) removeTipsForView: (NSView*)aView
{
GSToolTips *tt = (GSToolTips*)NSMapGet(viewsMap, (void*)aView);
if (tt != nil)
{
[tt removeAllToolTips];
NSMapRemove(viewsMap, (void*)aView);
}
}
+ (GSToolTips*) tipsForView: (NSView*)aView
{
GSToolTips *tt = (GSToolTips*)NSMapGet(viewsMap, (void*)aView);
if (tt == nil)
{
tt = [[GSToolTips alloc] initForView: aView];
NSMapInsert(viewsMap, (void*)aView, (void*)tt);
RELEASE(tt);
}
return tt;
}
- (NSToolTipTag) addToolTipRect: (NSRect)aRect
owner: (id)anObject
userData: (void *)data
{
NSTrackingRectTag tag;
GSTTProvider *provider;
if (timer != nil)
{
return -1; // A tip is already in progress.
}
if (NSEqualRects(aRect, NSZeroRect))
{
return -1; // No rectangle.
}
if (anObject == nil)
{
return -1; // No provider object.
}
provider = [[GSTTProvider alloc] initWithObject: anObject userData: data];
tag = [view addTrackingRect: aRect
owner: self
userData: provider
assumeInside: NO];
return tag;
}
- (unsigned) count
{
NSEnumerator *enumerator;
GSTrackingRect *rect;
unsigned count = 0;
enumerator = [((NSViewPtr)view)->_tracking_rects objectEnumerator];
while ((rect = [enumerator nextObject]) != nil)
{
if (rect->owner == self)
{
count++;
}
}
return count;
}
- (void) dealloc
{
[self _endDisplay];
[self removeAllToolTips];
[super dealloc];
}
- (id) initForView: (NSView*)aView
{
view = aView;
timer = nil;
window = nil;
toolTipTag = -1;
return self;
}
- (void) mouseEntered: (NSEvent *)theEvent
{
if (timer == nil)
{
GSTTProvider *provider = (GSTTProvider*)[theEvent userData];
NSString *toolTipString;
if ([[provider object] respondsToSelector:
@selector(view:stringForToolTip:point:userData:)] == YES)
{
toolTipString = [[provider object] view: view
stringForToolTip: [theEvent trackingNumber]
point: [theEvent locationInWindow]
userData: [provider data]];
}
else
{
toolTipString = [[provider object] description];
}
timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: @selector(_timedOut:)
userInfo: toolTipString
repeats: YES];
if ([[view window] acceptsMouseMovedEvents] == YES)
{
restoreMouseMoved = NO;
}
else
{
restoreMouseMoved = YES;
[[view window] setAcceptsMouseMovedEvents: YES];
}
[NSWindow _setToolTipVisible: self];
}
}
- (void) mouseExited: (NSEvent *)theEvent
{
[self _endDisplay];
}
- (void) mouseDown: (NSEvent *)theEvent
{
[self _endDisplay];
}
- (void) mouseMoved: (NSEvent *)theEvent
{
NSPoint mouseLocation;
NSPoint origin;
if (window == nil)
{
return;
}
mouseLocation = [NSEvent mouseLocation];
origin = NSMakePoint(mouseLocation.x + 8,
mouseLocation.y - 16 - [window frame].size.height);
[window setFrameOrigin: origin];
}
- (void) rebuild
{
NSEnumerator *enumerator;
GSTrackingRect *rect;
enumerator = [((NSViewPtr)view)->_tracking_rects objectEnumerator];
while ((rect = [enumerator nextObject]) != nil)
{
if (rect->owner == self)
{
GSTTProvider *provider = (GSTTProvider *)rect->user_data;
// FIXME can we do anything with tooltips other than the main one?
if (rect->tag == toolTipTag)
{
NSTrackingRectTag tag;
NSRect frame;
[view removeTrackingRect: rect->tag];
frame = [view frame];
frame.origin.x = 0;
frame.origin.y = 0;
tag = [view addTrackingRect: frame
owner: self
userData: provider
assumeInside: NO];
toolTipTag = tag;
}
}
}
}
- (void) removeAllToolTips
{
NSEnumerator *enumerator;
GSTrackingRect *rect;
[self _endDisplay];
enumerator = [((NSViewPtr)view)->_tracking_rects objectEnumerator];
while ((rect = [enumerator nextObject]) != nil)
{
if (rect->owner == self)
{
RELEASE((GSTTProvider*)rect->user_data);
[view removeTrackingRect: rect->tag];
}
}
toolTipTag = -1;
}
- (void) removeToolTip: (NSToolTipTag)tag
{
NSEnumerator *enumerator;
GSTrackingRect *rect;
enumerator = [((NSViewPtr)view)->_tracking_rects objectEnumerator];
while ((rect = [enumerator nextObject]) != nil)
{
if (rect->tag == tag && rect->owner == self)
{
RELEASE((GSTTProvider*)rect->user_data);
[view removeTrackingRect: tag];
}
}
}
- (void) setToolTip: (NSString *)string
{
if ([string length] == 0)
{
if (toolTipTag != -1)
{
[self _endDisplay];
[self removeToolTip: toolTipTag];
toolTipTag = -1;
}
}
else
{
GSTTProvider *provider;
if (toolTipTag == -1)
{
NSRect rect;
rect = [view frame];
rect.origin.x = 0;
rect.origin.y = 0;
provider = [[GSTTProvider alloc] initWithObject: string
userData: nil];
toolTipTag = [view addTrackingRect: rect
owner: self
userData: provider
assumeInside: NO];
}
else
{
NSEnumerator *enumerator;
GSTrackingRect *rect;
enumerator = [((NSViewPtr)view)->_tracking_rects objectEnumerator];
while ((rect = [enumerator nextObject]) != nil)
{
if (rect->tag == toolTipTag && rect->owner == self)
{
[((GSTTProvider*)rect->user_data) setObject: string];
}
}
}
}
}
- (NSString *) toolTip
{
NSEnumerator *enumerator;
GSTrackingRect *rect;
enumerator = [((NSViewPtr)view)->_tracking_rects objectEnumerator];
while ((rect = [enumerator nextObject]) != nil)
{
if (rect->tag == toolTipTag)
{
return [((GSTTProvider*)rect->user_data) object];
}
}
return nil;
}
@end
@implementation GSToolTips (Private)
- (void) _drawText: (NSAttributedString *)text
{
NSRectEdge sides[] = {NSMinXEdge, NSMaxYEdge, NSMaxXEdge, NSMinYEdge};
NSColor *black = [NSColor blackColor];
NSColor *colors[] = {black, black, black, black};
NSRect bounds = [[window contentView] bounds];
NSRect textRect;
textRect = [window frame];
textRect.origin.x = 2;
textRect.origin.y = -2;
[[window contentView] lockFocus];
[text drawInRect: textRect];
NSDrawColorTiledRects(bounds, bounds, sides, colors, 4);
[[window contentView] unlockFocus];
}
- (void) _endDisplay
{
if ([NSWindow _toolTipVisible] == self)
{
[NSWindow _setToolTipVisible: nil];
}
if (timer != nil)
{
if ([timer isValid])
{
[timer invalidate];
}
timer = nil;
}
if (window != nil)
{
[window close];
window = nil;
}
if (restoreMouseMoved == YES)
{
restoreMouseMoved = NO;
[[view window] setAcceptsMouseMovedEvents: NO];
}
}
- (void) _timedOut: (NSTimer *)aTimer
{
NSString *toolTipString = [aTimer userInfo];
if (timer != nil)
{
if ([timer isValid])
{
[timer invalidate];
}
timer = nil;
}
if (window == nil)
{
NSAttributedString *toolTipText = nil;
NSSize textSize;
NSPoint mouseLocation = [NSEvent mouseLocation];
NSRect windowRect;
NSColor *color;
NSMutableDictionary *attributes;
attributes = [NSMutableDictionary dictionary];
[attributes setObject: [NSFont systemFontOfSize: 10.0]
forKey: NSFontAttributeName];
toolTipText =
[[NSAttributedString alloc] initWithString: toolTipString
attributes: attributes];
textSize = [toolTipText size];
// Window
windowRect = NSMakeRect(mouseLocation.x + 8,
mouseLocation.y - 16 - (textSize.height+3),
textSize.width + 4, textSize.height + 4);
window = [[NSWindow alloc] initWithContentRect: windowRect
styleMask: NSBorderlessWindowMask
backing: NSBackingStoreRetained
defer: YES];
color
= [NSColor colorWithDeviceRed: 1.0 green: 1.0 blue: 0.90 alpha: 1.0];
[window setBackgroundColor: color];
[window setReleasedWhenClosed: YES];
[window setExcludedFromWindowsMenu: YES];
[window setLevel: NSStatusWindowLevel];
[window orderFront: nil];
[self _drawText: toolTipText];
RELEASE(toolTipText);
}
}
@end

View file

@ -69,6 +69,7 @@
#include "GNUstepGUI/GSDisplayServer.h"
#include "GNUstepGUI/GSTrackingRect.h"
#include "GNUstepGUI/GSVersion.h"
#include "GSToolTips.h"
/*
* We need a fast array that can store objects without retain/release ...
@ -325,7 +326,12 @@ GSSetDragTypes(NSView* obj, NSArray *types)
fromView: _super_view];
_visibleRect = NSIntersectionRect(superviewsVisibleRect, _bounds);
}
if (_rFlags.has_tooltips != 0)
{
GSToolTips *tt = [GSToolTips tipsForView: self];
[tt rebuild];
}
}
}
@ -521,7 +527,7 @@ GSSetDragTypes(NSView* obj, NSArray *types)
/*
* Now we clean up all views which have us as their previous view.
* We also relase the memory we used.
* We also release the memory we used.
*/
if (nKV(self) != 0)
{
@ -556,12 +562,16 @@ GSSetDragTypes(NSView* obj, NSArray *types)
RELEASE(_frameMatrix);
RELEASE(_boundsMatrix);
TEST_RELEASE(_sub_views);
TEST_RELEASE(_tracking_rects);
if (_rFlags.has_tooltips != 0)
{
[GSToolTips removeTipsForView: self];
}
if (_rFlags.has_currects != 0)
{
[self discardCursorRects]; // Handle release of cursors
}
TEST_RELEASE(_cursor_rects);
TEST_RELEASE(_tracking_rects);
[self unregisterDraggedTypes];
[self releaseGState];
@ -4313,23 +4323,47 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
owner: (id)anObject
userData: (void *)data
{
return 0;
GSToolTips *tt = [GSToolTips tipsForView: self];
_rFlags.has_tooltips = 1;
return [tt addToolTipRect: aRect owner: anObject userData: data];
}
- (void) removeAllToolTips
{
if (_rFlags.has_tooltips == 1)
{
GSToolTips *tt = [GSToolTips tipsForView: self];
[tt removeAllToolTips];
}
}
- (void) removeToolTip: (NSToolTipTag)tag
{
if (_rFlags.has_tooltips == 1)
{
GSToolTips *tt = [GSToolTips tipsForView: self];
[tt removeToolTip: tag];
}
}
- (void) setToolTip: (NSString *)string
{
GSToolTips *tt = [GSToolTips tipsForView: self];
[tt setToolTip: string];
}
- (NSString *) toolTip
{
if (_rFlags.has_tooltips == 1)
{
GSToolTips *tt = [GSToolTips tipsForView: self];
return [tt toolTip];
}
return nil;
}

View file

@ -75,6 +75,9 @@
#include "GNUstepGUI/GSTrackingRect.h"
#include "GNUstepGUI/GSDisplayServer.h"
#include "GNUstepGUI/GSToolbarView.h"
#include "GSToolTips.h"
static GSToolTips *toolTipVisible = nil;
#include "GSWindowDecorationView.h"
@ -96,11 +99,14 @@ BOOL GSViewAcceptsDrag(NSView *v, id<NSDraggingInfo> dragInfo);
/*
* Category for internal methods (for use only within the NSWindow class itself
* or with other AppKit classes in the case of the _windowView method)
* or with other AppKit classes.
*/
@interface NSWindow (GNUstepPrivate)
+(void) _addAutodisplayedWindow: (NSWindow *)w;
+(void) _removeAutodisplayedWindow: (NSWindow *)w;
+ (void) _addAutodisplayedWindow: (NSWindow *)w;
+ (void) _removeAutodisplayedWindow: (NSWindow *)w;
+ (void) _setToolTipVisible: (GSToolTips*)t;
+ (GSToolTips*) _toolTipVisible;
- (void) _lossOfKeyOrMainWindow;
- (NSView *) _windowView;
@ -109,6 +115,15 @@ BOOL GSViewAcceptsDrag(NSView *v, id<NSDraggingInfo> dragInfo);
@implementation NSWindow (GNUstepPrivate)
+ (void) _setToolTipVisible: (GSToolTips*)t
{
toolTipVisible = t;
}
+ (GSToolTips*) _toolTipVisible
{
return toolTipVisible;
}
/* Window autodisplay machinery. */
- (void) _handleAutodisplay
@ -3183,6 +3198,13 @@ resetCursorRectsForView(NSView *theView)
else
{
ASSIGN(_lastView, v);
if (toolTipVisible != nil)
{
/* Inform the tooltips system that we have had
* a mouse down so it should stop displaying.
*/
[toolTipVisible mouseDown: theEvent];
}
[v mouseDown: theEvent];
}
}
@ -3253,7 +3275,19 @@ resetCursorRectsForView(NSView *theView)
* forward the mouse movement to the correct view.
*/
v = [_wv hitTest: [theEvent locationInWindow]];
[v mouseMoved: theEvent];
/* If the view is displaying a tooltip, we should
* send mouse movements to the tooltip system so
* that the window can track the mouse.
*/
if (toolTipVisible != nil)
{
[toolTipVisible mouseMoved: theEvent];
}
else
{
[v mouseMoved: theEvent];
}
}
break;
}