1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/window.mm
3 // Purpose: widgets (non tlw) for cocoa
4 // Author: Stefan Csomor
7 // RCS-ID: $Id: window.mm 48805 2007-09-19 14:52:25Z SC $
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
14 #include <Cocoa/Cocoa.h>
17 #include "wx/osx/private.h"
22 @interface wxNSView : NSView
27 - (void)drawRect: (NSRect) rect;
29 -(void)mouseDown:(NSEvent *)event ;
30 -(void)rightMouseDown:(NSEvent *)event ;
31 -(void)otherMouseDown:(NSEvent *)event ;
32 -(void)mouseUp:(NSEvent *)event ;
33 -(void)rightMouseUp:(NSEvent *)event ;
34 -(void)otherMouseUp:(NSEvent *)event ;
35 -(void)handleMouseEvent:(NSEvent *)event;
37 - (void)setImplementation: (wxWidgetImpl *) theImplementation;
38 - (wxWidgetImpl*) implementation;
40 - (BOOL) becomeFirstResponder;
41 - (BOOL) resignFirstResponder;
45 void SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
47 UInt32 modifiers = [nsEvent modifierFlags] ;
48 wxPoint screenMouseLocation = wxFromNSPoint( NULL, [nsEvent locationInWindow]);
50 // these parameters are not given for all events
51 UInt32 button = [nsEvent buttonNumber];
52 UInt32 clickCount = [nsEvent clickCount];
53 UInt32 mouseChord = 0; // TODO does this exist for cocoa
55 wxevent.m_x = screenMouseLocation.x;
56 wxevent.m_y = screenMouseLocation.y;
57 wxevent.m_shiftDown = modifiers & NSShiftKeyMask;
58 wxevent.m_controlDown = modifiers & NSControlKeyMask;
59 wxevent.m_altDown = modifiers & NSAlternateKeyMask;
60 wxevent.m_metaDown = modifiers & NSCommandKeyMask;
61 wxevent.m_clickCount = clickCount;
62 wxevent.SetTimestamp( [nsEvent timestamp] ) ;
64 // a control click is interpreted as a right click
65 bool thisButtonIsFakeRight = false ;
66 if ( button == kEventMouseButtonPrimary && (modifiers & controlKey) )
68 button = kEventMouseButtonSecondary ;
69 thisButtonIsFakeRight = true ;
72 // otherwise we report double clicks by connecting a left click with a ctrl-left click
73 if ( clickCount > 1 && button != g_lastButton )
75 // we must make sure that our synthetic 'right' button corresponds in
76 // mouse down, moved and mouse up, and does not deliver a right down and left up
78 if ( cEvent.GetKind() == kEventMouseDown )
80 g_lastButton = button ;
81 g_lastButtonWasFakeRight = thisButtonIsFakeRight ;
87 g_lastButtonWasFakeRight = false ;
89 else if ( g_lastButton == kEventMouseButtonSecondary && g_lastButtonWasFakeRight )
90 button = g_lastButton ;
92 // Adjust the chord mask to remove the primary button and add the
93 // secondary button. It is possible that the secondary button is
94 // already pressed, e.g. on a mouse connected to a laptop, but this
95 // possibility is ignored here:
96 if( thisButtonIsFakeRight && ( mouseChord & 1U ) )
97 mouseChord = ((mouseChord & ~1U) | 2U);
100 wxevent.m_leftDown = true ;
102 wxevent.m_rightDown = true ;
104 wxevent.m_middleDown = true ;
107 // translate into wx types
108 int eventType = [nsEvent type];
111 case NSLeftMouseDown :
112 case NSRightMouseDown :
113 case NSOtherMouseDown :
117 wxevent.SetEventType( clickCount > 1 ? wxEVT_LEFT_DCLICK : wxEVT_LEFT_DOWN ) ;
121 wxevent.SetEventType( clickCount > 1 ? wxEVT_RIGHT_DCLICK : wxEVT_RIGHT_DOWN ) ;
125 wxevent.SetEventType( clickCount > 1 ? wxEVT_MIDDLE_DCLICK : wxEVT_MIDDLE_DOWN ) ;
134 case NSRightMouseUp :
135 case NSOtherMouseUp :
139 wxevent.SetEventType( wxEVT_LEFT_UP ) ;
143 wxevent.SetEventType( wxEVT_RIGHT_UP ) ;
147 wxevent.SetEventType( wxEVT_MIDDLE_UP ) ;
157 wxevent.SetEventType( wxEVT_MOUSEWHEEL ) ;
159 EventMouseWheelAxis axis = cEvent.GetParameter<EventMouseWheelAxis>(kEventParamMouseWheelAxis, typeMouseWheelAxis) ;
160 SInt32 delta = cEvent.GetParameter<SInt32>(kEventParamMouseWheelDelta, typeSInt32) ;
162 wxevent.m_wheelRotation = 10; // delta;
163 wxevent.m_wheelDelta = 1;
164 wxevent.m_linesPerAction = 1;
165 if ( 0 /* axis == kEventMouseWheelAxisX*/ )
166 wxevent.m_wheelAxis = 1;
170 case NSMouseEntered :
172 case NSLeftMouseDragged :
173 case NSRightMouseDragged :
174 case NSOtherMouseDragged :
176 wxevent.SetEventType( wxEVT_MOTION ) ;
183 @implementation wxNSView
185 - (void)drawRect: (NSRect) rect
189 CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
190 CGContextSaveGState( context );
191 CGContextBeginPath( context );
192 CGContextMoveToPoint(context, 0, 0);
193 NSRect bounds = [self bounds];
194 CGContextAddLineToPoint(context, 10, 0);
195 CGContextMoveToPoint(context, 0, 0);
196 CGContextAddLineToPoint(context, 0, 10);
197 CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
198 CGContextAddLineToPoint(context, bounds.size.width, bounds.size.height-10);
199 CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
200 CGContextAddLineToPoint(context, bounds.size.width-10, bounds.size.height);
201 CGContextClosePath( context );
202 CGContextStrokePath(context);
204 if ( [ self isFlipped ] == NO )
206 CGContextTranslateCTM( context, 0, [self bounds].size.height );
207 CGContextScaleCTM( context, 1, -1 );
209 m_impl->GetWXPeer()->MacSetCGContextRef( context );
212 event.SetTimestamp(0); // todo
213 event.SetEventObject(m_impl->GetWXPeer());
214 m_impl->GetWXPeer()->HandleWindowEvent(event);
216 CGContextRestoreGState( context );
220 -(void)mouseDown:(NSEvent *)event
222 [self handleMouseEvent:event];
225 -(void)rightMouseDown:(NSEvent *)event
227 [self handleMouseEvent:event];
230 -(void)otherMouseDown:(NSEvent *)event
232 [self handleMouseEvent:event];
235 -(void)mouseUp:(NSEvent *)event
237 [self handleMouseEvent:event];
240 -(void)rightMouseUp:(NSEvent *)event
242 [self handleMouseEvent:event];
245 -(void)otherMouseUp:(NSEvent *)event
247 [self handleMouseEvent:event];
250 -(void)handleMouseEvent:(NSEvent *)event
252 NSPoint clickLocation;
253 clickLocation = [self convertPoint:[event locationInWindow] fromView:nil];
254 wxPoint pt = wxFromNSPoint( self, clickLocation );
255 wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
256 SetupMouseEvent( wxevent , event ) ;
259 m_impl->GetWXPeer()->HandleWindowEvent(wxevent);
262 - (void)setImplementation: (wxWidgetImpl *) theImplementation
264 m_impl = theImplementation;
267 - (wxWidgetImpl*) implementation
277 - (BOOL) becomeFirstResponder
279 BOOL r = [super becomeFirstResponder];
286 - (BOOL) resignFirstResponder
288 BOOL r = [super resignFirstResponder];
298 IMPLEMENT_DYNAMIC_CLASS( wxWidgetCocoaImpl , wxWidgetImpl )
300 wxWidgetCocoaImpl::wxWidgetCocoaImpl( wxWindowMac* peer , WXWidget w, bool isRootControl ) :
301 wxWidgetImpl( peer, isRootControl ), m_osxView(w)
305 wxWidgetCocoaImpl::wxWidgetCocoaImpl()
309 void wxWidgetCocoaImpl::Init()
314 wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
316 [m_osxView setImplementation:NULL];
320 bool wxWidgetCocoaImpl::IsVisible() const
322 return [m_osxView isHiddenOrHasHiddenAncestor] == NO;
325 void wxWidgetCocoaImpl::Raise()
329 void wxWidgetCocoaImpl::Lower()
333 void wxWidgetCocoaImpl::ScrollRect( const wxRect *rect, int dx, int dy )
337 void wxWidgetCocoaImpl::Move(int x, int y, int width, int height)
339 NSRect r = wxToNSRect( [m_osxView superview], wxRect(x,y,width, height) );
340 [m_osxView setFrame:r];
343 void wxWidgetCocoaImpl::GetPosition( int &x, int &y ) const
345 wxRect r = wxFromNSRect( [m_osxView superview], [m_osxView frame] );
350 void wxWidgetCocoaImpl::GetSize( int &width, int &height ) const
352 NSRect rect = [m_osxView frame];
353 width = rect.size.width;
354 height = rect.size.height;
357 void wxWidgetCocoaImpl::GetContentArea( int&left, int &top, int &width, int &height )
360 GetSize( width, height );
363 void wxWidgetCocoaImpl::SetNeedsDisplay( const wxRect* where )
366 [m_osxView setNeedsDisplayInRect:wxToNSRect(m_osxView, *where )];
368 [m_osxView setNeedsDisplay:YES];
371 bool wxWidgetCocoaImpl::GetNeedsDisplay() const
373 return [m_osxView needsDisplay];
376 void wxWidgetCocoaImpl::CanFocus() const
378 return [m_osxView acceptsFirstResponder] == YES;
381 bool wxWidgetCocoaImpl::HasFocus() const
383 return [m_osxView isFirstResponder] == YES;
386 bool wxWidgetCocoaImpl::SetFocus()
388 [m_osxView makeKeyWindow] ;
392 void wxWidgetCocoaImpl::RemoveFromParent()
394 [m_osxView removeFromSuperview];
397 void wxWidgetCocoaImpl::Embed( wxWidgetImpl *parent )
399 NSView* container = parent->GetWXWidget() ;
400 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
401 [container addSubview:m_osxView];
409 wxWidgetImpl* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer, const wxPoint& pos, const wxSize& size,
410 long style, long extraStyle, const wxString& name)
412 NSView* sv = (wxpeer->GetParent()->GetHandle() );
414 NSRect r = wxToNSRect( sv, wxRect( pos, size) );
415 // Rect bounds = wxMacGetBoundsForControl( wxpeer, pos , size ) ;
416 wxNSView* v = [[wxNSView alloc] initWithFrame:r];
418 wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v );
419 [v setImplementation:c];
423 wxWidgetImpl* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
425 NSWindow* tlw = now->GetWXWindow();
426 wxNSView* v = [[wxNSView alloc] initWithFrame:[[tlw contentView] frame]];
427 wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( now, v, true );
428 [v setImplementation:c];
429 [tlw setContentView:v];