Fix placement of auxiliary IM window for Core Text
[MacVim.git] / src / MacVim / PlugInGUI.m
blobb1e272002d1aea54e15b80c248425b17e6de2fc2
1 /* vi:set ts=8 sts=4 sw=4 ft=objc:
2  *
3  * VIM - Vi IMproved            by Bram Moolenaar
4  *                              MacVim GUI port by Bjorn Winckler
5  *
6  * Do ":help uganda"  in Vim to read copying and usage conditions.
7  * Do ":help credits" in Vim to see a list of people who contributed.
8  * See README.txt for an overview of the Vim source code.
9  */
12  * MMPlugInViewHeader
13  *
14  * Essentially just a title bar for a plugin view.  Handles drawing the
15  * drag-and-drop line where a new plugin view will be inserted.
16  *
17  * MMPlugInView
18  *
19  * This contains a single view added by a plugin.
20  *
21  * MMPlugInViewContainer
22  *
23  * This contains multiple MMPlugInViews.  It handles the drag and drop aspects
24  * of the views, as well.
25  *
26  * Author: Matt Tolton
27  */
28 #import "MacVim.h"
30 #ifdef MM_ENABLE_PLUGINS
32 #import "PlugInGUI.h"
33 #import "CTGradient.h"
35 NSString *MMPlugInViewPboardType = @"MMPlugInViewPboardType";
37 @implementation MMPlugInViewHeader
39 - (void)mouseDown:(NSEvent *)theEvent
41     // Make image from view
42     NSView *view = self;
43     [view lockFocus];
44     NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc]
45         initWithFocusedViewRect: [view bounds]] autorelease];
46     [view unlockFocus];
48     NSImage *image = [[[NSImage alloc] initWithSize: [view bounds].size]
49                         autorelease];
50     [image addRepresentation:bitmap];
52     NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
54     [pboard declareTypes:[NSArray arrayWithObject:MMPlugInViewPboardType]
55                    owner:self];
57     NSPoint pt = [view convertPoint:[view bounds].origin
58                              toView:[controller plugInSubview]];
59     [[controller plugInSubview] dragImage:image
60                                        at:pt
61                                    offset:NSMakeSize(0, 0)
62                                     event:theEvent
63                                pasteboard:pboard
64                                    source:controller
65                                 slideBack:YES];
68 - (void)drawRect:(NSRect)rect
70     NSColor *startColor;
71     startColor = [NSColor colorWithCalibratedRed:.600
72                                            green:.600
73                                             blue:.600
74                                            alpha:1.0];
76     NSColor *endColor = [NSColor colorWithCalibratedRed:.800
77                                                   green:.800
78                                                    blue:.800
79                                                   alpha:1.0];
81     CTGradient *grad = [CTGradient gradientWithBeginningColor:startColor
82                                                   endingColor:endColor];
83     [grad fillRect:[self bounds] angle:90];
85     MMPlugInView *dropView = [[controller container] dropView];
87     if (dropView == [controller plugInSubview]) {
88         NSRect insertionRect = NSMakeRect(0,[self bounds].size.height - 2,
89                 [self bounds].size.width, 2);
90         [[NSColor redColor] set];
91         NSRectFill(insertionRect);
92     }
95 - (BOOL)isOpaque
97     return YES;
100 - (NSRect)dragRect
102     return NSMakeRect(0, [self bounds].size.height - 6, [self bounds].size.width, 6);
105 @end
107 @implementation MMPlugInView
109 - (MMPlugInViewController *)controller
111     return controller;
114 @end
116 @implementation MMPlugInViewController
118 - (id)initWithView:(NSView *)view title:(NSString *)title
120     if ((self = [super init]) == nil) return nil;
122     if (![NSBundle loadNibNamed:@"PlugInView" owner:self])
123         ASLogErr(@"Error loading PlugIn nib");
125     [titleField setStringValue:title];
127     [plugInSubview setMinDimension:50
128                    andMaxDimension:0.0];
130     [view setFrame:[contentView bounds]];
131     [contentView addSubview:view];
133     return self;
136 - (RBSplitSubview *)plugInSubview
138     return plugInSubview;
141 - (void)moveToContainer:(MMPlugInViewContainer *)container
143     if ([plugInSubview splitView]) {
144         [plugInSubview removeFromSuperview];
145     }
146     [container addSubview:plugInSubview];
149 - (void)moveToContainer:(MMPlugInViewContainer *)container before:(MMPlugInView *)lowerView
151     if ([plugInSubview splitView]) {
152         [plugInSubview removeFromSuperview];
153     }
154     [container addSubview:plugInSubview positioned:NSWindowBelow relativeTo:lowerView];
157 - (MMPlugInViewHeader *)headerView
159     return headerView;
162 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
164     if (isLocal)
165         return NSDragOperationPrivate;
166     else
167         return NSDragOperationNone;
170 - (void)dropViewChanged {
171     [headerView setNeedsDisplay:YES];
174 - (MMPlugInViewContainer *)container {
175     return (MMPlugInViewContainer *)[plugInSubview splitView];
177 @end
179 @implementation MMPlugInViewContainer
181 - (id)initWithFrame:(NSRect)frame
183     if ((self = [super initWithFrame:frame]) == nil) return nil;
185     [self registerForDraggedTypes:
186             [NSArray arrayWithObjects:MMPlugInViewPboardType, nil]];
188     [self setVertical:NO];
189     [self setDelegate:self];
191     fillerView = [[RBSplitSubview alloc] initWithFrame:NSMakeRect(0,0,0,0)];
192     [fillerView setHidden:YES];
194     return self;
197 - (void)dealloc
199     ASLogDebug(@"");
201     [fillerView release]; fillerView = nil;
202     [super dealloc];
205 - (unsigned int)splitView:(RBSplitView*)sender dividerForPoint:(NSPoint)point
206                 inSubview:(RBSplitSubview*)subview
208     MMPlugInViewController *controller = [(MMPlugInView *)subview controller];
209     MMPlugInViewHeader *header = [controller headerView];
211     if ([header mouse:[header convertPoint:point fromView:sender]
212                inRect:[header dragRect]])
213         return [subview position] - 1;
215     return NSNotFound;
218 - (NSRect)splitView:(RBSplitView*)sender cursorRect:(NSRect)rect
219          forDivider:(unsigned int)theDivider
222     if (theDivider != 0) return NSZeroRect;
224     int i;
225     for (i = 1;; i++) {
226         MMPlugInView *view = (MMPlugInView *)[sender subviewAtPosition:i];
227         if (!view) break;
229         MMPlugInViewHeader *header = [[view controller] headerView];
230         NSRect rect = [header dragRect];
231         rect = [sender convertRect:rect fromView:header];
232         [sender addCursorRect:rect
233                        cursor:[RBSplitView cursor:RBSVHorizontalCursor]];
235     }
237     return NSZeroRect;
240 - (void)clearDragInfo
242     if (dropView) {
243         MMPlugInView *save = dropView;
244         dropView = nil;
245         [[save controller] dropViewChanged];
246     }
249 // point should be in the window's coordinate system
250 - (void)updateDragInfo:(id<NSDraggingInfo>)info
253     [self clearDragInfo];
255     if (!([info draggingSourceOperationMask] & NSDragOperationPrivate)) return;
257     if (![[info draggingSource] isKindOfClass:[MMPlugInViewController class]]) return; 
259     // for now has to be THIS container.  in the future, it will be ok for any
260     // container associated with the same vim instance
261     if ([[info draggingSource] container] != self) return;
263     // XXX for now we just use the view that the mouse is currently over, and
264     // always insert "above" that view.  In the future, we might want to try to
265     // find the divider that the mouse is closest to and have the dropView be
266     // the view below that divider.
268     NSPoint point = [info draggingLocation];
270     int i;
271     for (i = 0;; i++) {
272         MMPlugInView *subview = (MMPlugInView *)[self subviewAtPosition:i];
273         if (!subview) break;
275         if ([subview mouse:[subview convertPoint:point fromView:nil]
276                     inRect:[subview bounds]]) {
277             dropView = subview;
278             break;
279         }
280     }
282     if ([[info draggingSource] plugInSubview] == dropView)
283         dropView = nil;
285     if (dropView) [[dropView controller] dropViewChanged];
288 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
290     [self updateDragInfo:sender];
292     if (dropView != nil)
293         return NSDragOperationPrivate;
294     else
295         return NSDragOperationNone;
298 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
300     [self updateDragInfo:sender];
302     if (dropView != nil)
303         return NSDragOperationPrivate;
305     return NSDragOperationNone;
308 - (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)sender
310     [self updateDragInfo:sender];
311     return dropView != nil;
314 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
316     MMPlugInViewController *source = [sender draggingSource];
317     [source moveToContainer:self before:dropView];
318     [self clearDragInfo];
319     return YES;
322 - (void)draggingExited:(id<NSDraggingInfo>)sender
324     [self clearDragInfo];
328 - (MMPlugInView *)dropView {
329     return dropView;
332 @end
334 #endif