root/tags/2C11/AICustomTabDragging.m

Revision 2039, 8.2 kB (checked in by timothy, 4 years ago)

Latest Adium tab code. Merged our tooltip code in.

Line 
1 //
2 //  AICustomTabDragging.m
3 //  Adium
4 //
5 //  Created by Adam Iser on Sat Mar 06 2004.
6 //  Copyright (c) 2004 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "AICustomTabDragging.h"
10 #import "AICustomTabDragWindow.h"
11 #import "AICustomTabsView.h"
12 #import "AICustomTabCell.h"
13
14 #define CUSTOM_TABS_INDENT              3                                       //Indent on left and right of tabbar
15
16 @interface AICustomTabDragging (PRIVATE)
17 + (NSImage *)dragTabImageForTabCell:(AICustomTabCell *)tabCell inCustomTabsView:(AICustomTabsView *)customTabsView;
18 + (NSImage *)dragWindowImageForWindow:(NSWindow *)window customTabsView:(AICustomTabsView *)customTabsView tabCell:(AICustomTabCell *)tabCell;
19 - (void)cleanupDrag;
20 @end
21
22 @implementation AICustomTabDragging
23
24 static AICustomTabDragging *sharedTabDragInstance = nil;
25 + (AICustomTabDragging *)sharedInstance
26 {
27         if(!sharedTabDragInstance) sharedTabDragInstance = [[self alloc] init];
28         return(sharedTabDragInstance);
29 }
30
31 //Init
32 - (id)init
33 {
34         [super init];
35         _destinationOfLastDrag = nil;
36         dragTabCell = nil;
37         sourceTabBar = nil;
38         destTabBar = nil;
39         tabDragWindow = nil;
40        
41         return(self);
42 }
43
44 //Set the currently hovered destination tab view
45 - (void)setDestinationTabView:(AICustomTabsView *)inDest
46 {
47         if(inDest != destTabBar){
48                 [destTabBar release];
49                 destTabBar = [inDest retain];
50         }
51         [tabDragWindow setDisplayingFullWindow:(!destTabBar) animate:YES];
52 }
53
54 //Set the currently hovered destination tab view
55 - (AICustomTabsView *)destinationTabView
56 {
57         return(destTabBar);
58 }
59
60 //Set the currently active source tab view
61 - (AICustomTabsView *)sourceTabView
62 {
63         return(sourceTabBar);
64 }
65
66 //Set the currently hovered screen point
67 - (void)setDestinationHoverPoint:(NSPoint)inPoint
68 {
69         [tabDragWindow moveToPoint:inPoint];
70 }
71
72 //Size of the cell being dragged
73 - (NSSize)sizeOfDraggedCell
74 {
75         return([dragTabCell frame].size);
76 }
77
78
79 //Drag Start/Stop --------------------------------------------------------------------------------------------------------
80 #pragma mark Drag Start/Stop
81 //Initiate a drag
82 - (void)dragTabCell:(AICustomTabCell *)inTabCell fromCustomTabsView:(AICustomTabsView *)sourceView withEvent:(NSEvent *)inEvent selectTab:(BOOL)shouldSelect
83 {
84     NSPasteboard        *pboard;
85     NSPoint                     clickLocation = [inEvent locationInWindow];
86     NSPoint                     startPoint;
87     BOOL                        sourceWindowWillHide;
88    
89         //Post the dragging will begin notification
90         [[NSNotificationCenter defaultCenter] postNotificationName:AICustomTabDragWillBegin object:self];
91        
92         //Setup
93         [destTabBar release]; destTabBar = nil;
94         sourceTabBar = [sourceView retain];
95         dragTabCell = [inTabCell retain];
96         selectTabAfterDrag = shouldSelect;
97        
98         //Determine if the source window will hide as a result of this drag
99         sourceWindowWillHide = ([sourceTabBar removingLastTabHidesWindow] && [sourceTabBar numberOfTabViewItems] == 1);
100         if(!sourceWindowWillHide){
101                 destTabBar = [sourceView retain];
102         }
103        
104         //Adjust the drag offset so the cursor is atleast always touching the tab drag image
105         int width = [inTabCell frame].size.width;
106         int height = [inTabCell frame].size.height;
107        
108         dragOffset = NSMakeSize([inTabCell frame].origin.x - clickLocation.x, [inTabCell frame].origin.y - clickLocation.y);
109         if(dragOffset.width > width) dragOffset.width = width;
110         if(dragOffset.width < -width) dragOffset.width = -width;
111         if(dragOffset.height > height) dragOffset.height = height;
112         if(dragOffset.height < -height) dragOffset.height = -height;
113        
114         //Create the drag window for our custom drag tracking
115         tabDragWindow = [AICustomTabDragWindow dragWindowForCustomTabView:sourceView
116                                                                                                                                  cell:inTabCell
117                                                                                                                   transparent:!([sourceTabBar removingLastTabHidesWindow])];
118         [tabDragWindow setDisplayingFullWindow:sourceWindowWillHide animate:NO];
119        
120         //Position the drag window
121         startPoint = [[inEvent window] convertBaseToScreen:[inEvent locationInWindow]];
122         startPoint = NSMakePoint(startPoint.x + dragOffset.width, startPoint.y + dragOffset.height);
123         [tabDragWindow moveToPoint:startPoint];
124        
125         //Hide the source window
126         if(sourceWindowWillHide){
127                 [[sourceTabBar window] setAlphaValue:0.0];
128         }
129        
130         //Perform the drag
131         pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
132         [pboard declareTypes:[NSArray arrayWithObjects:TAB_CELL_IDENTIFIER, nil] owner:self];
133         [pboard setString:TAB_CELL_IDENTIFIER forType:TAB_CELL_IDENTIFIER];
134         [[inEvent window] dragImage:[tabDragWindow dragImage]
135                                                          at:NSMakePoint(clickLocation.x + dragOffset.width, clickLocation.y + dragOffset.height)
136                                                  offset:NSMakeSize(0,0)
137                                                   event:inEvent
138                                          pasteboard:pboard
139                                                  source:self
140                                           slideBack:NO];
141        
142         //Sneaky Bug Fix ---
143         //After dropping a tab into a tab bar, the tabbar's cursor tracking is rebuilt.  Unfortunately, since the floating
144         //window (With an image of the tab) used for dragging is still over the tab bar, any cursor rects we attempt to
145         //install below it will not work.  A sneaky solution to this is to remember the destination tab bar of the drag,
146         //and reset it's cursor tracking again, after the drag window has closed.
147         [tabDragWindow closeWindow];
148         if(_destinationOfLastDrag){
149                 [_destinationOfLastDrag resetCursorTracking];
150                 [_destinationOfLastDrag release]; _destinationOfLastDrag= nil;
151         }
152        
153 }
154
155 //End a drag
156 - (void)acceptDragIntoTabView:(AICustomTabsView *)destTabView atIndex:(int)destIndex
157 {       
158         if(destTabView == sourceTabBar){
159                 //Tab re-arranging we handle internally
160                 [sourceTabBar moveTab:[dragTabCell tabViewItem] toIndex:destIndex selectTab:selectTabAfterDrag animate:NO];
161
162         }else{
163                 //Moving tabs between bars is handled by the tab view delegate
164                 if([[sourceTabBar delegate] respondsToSelector:@selector(customTabView:didMoveTabViewItem:toCustomTabView:index:screenPoint:)]){
165                         [[sourceTabBar delegate] customTabView:sourceTabBar
166                                                                 didMoveTabViewItem:[dragTabCell tabViewItem]
167                                                                    toCustomTabView:destTabView
168                                                                                          index:destIndex
169                                                                            screenPoint:NSMakePoint(-1,-1)];
170                 }
171         }
172        
173         //Remember the dest tab bar so we can reset cursor tracking (see dragTabCell:fromCustomTabsView:withEvent:)
174         _destinationOfLastDrag = [destTabBar retain];
175         [self cleanupDrag];
176
177         //Post the dragging did finish notification
178         [[NSNotificationCenter defaultCenter] postNotificationName:AICustomTabDragDidComplete object:self];
179 }
180
181
182 //Drag Tracking --------------------------------------------------------------------------------------------------------
183 #pragma mark Drag Tracking (Source)
184 //Invoked in the dragging source as the drag begins
185 - (void)draggedImage:(NSImage *)image beganAt:(NSPoint)screenPoint
186 {
187     [self draggedImage:image movedTo:screenPoint];
188 }
189
190 //Invoked in the dragging source as the drag moves
191 - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint
192 {
193         [tabDragWindow setDisplayingFullWindow:(!destTabBar) animate:YES];
194        
195     if(!destTabBar){
196         [tabDragWindow moveToPoint:screenPoint];
197     }
198 }
199
200 //Invoked in the dragging source as the drag ends
201 - (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation
202 {       
203         if(operation == NSDragOperationNone){ //when dropped on the screen
204                 //Sneaky Bug Fix ---
205                 //If a drag is done very quickly, the system will fail to send our tab bar a draggingExited event, even though
206                 //the drag DID exit.  If this hapens, destTabBar will not be nil when we reach this method.  If the drag
207                 //opearation is 0, we know the tab was dropped somewhere on the screen.  So, if there is a value in destTabBar
208                 //we can assume it's a tab bar the system failed to send a draggingExited event, and send it ourself.
209                 if(destTabBar) [destTabBar draggingExited:nil];
210                
211                 screenPoint.x -= CUSTOM_TABS_INDENT;
212         if([[sourceTabBar delegate] respondsToSelector:@selector(customTabView:didMoveTabViewItem:toCustomTabView:index:screenPoint:)]){
213             [[sourceTabBar delegate] customTabView:sourceTabBar didMoveTabViewItem:[dragTabCell tabViewItem] toCustomTabView:nil index:-1 screenPoint:screenPoint];
214         }
215     }
216        
217     //Cleanup drag
218         [self cleanupDrag];
219 }
220
221 //Prevent dragging of tabs to another application
222 - (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)isLocal
223 {
224     return(isLocal ? NSDragOperationEvery : NSDragOperationNone);
225 }
226
227 //Clean up drag variables
228 - (void)cleanupDrag
229 {
230         [dragTabCell release]; dragTabCell = nil;
231         [destTabBar release]; destTabBar = nil;
232         [sourceTabBar release]; sourceTabBar = nil;             
233 }
234
235 - (NSTabViewItem *)draggedTabViewItem
236 {
237         return([dragTabCell tabViewItem]);
238 }
239
240 @end
Note: See TracBrowser for help on using the browser.