]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/window.mm
f2f51d18d9734a82db61df867ccd157b620d783a
[wxWidgets.git] / src / osx / cocoa / window.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/window.mm
3 // Purpose: widgets (non tlw) for cocoa
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 2008-06-20
7 // RCS-ID: $Id: window.mm 48805 2007-09-19 14:52:25Z SC $
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include <Cocoa/Cocoa.h>
15
16 #ifdef __WXMAC__
17 #include "wx/osx/private.h"
18 #endif
19
20 NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
21 {
22 int x, y, w, h ;
23
24 window->MacGetBoundsForControl( pos , size , x , y, w, h , adjustForOrigin ) ;
25 wxRect bounds(x,y,w,h);
26 NSView* sv = (window->GetParent()->GetHandle() );
27
28 return wxToNSRect( sv, bounds );
29 }
30
31 @interface wxNSView : NSView
32 {
33 wxWidgetImpl* impl;
34 }
35
36 - (void)drawRect: (NSRect) rect;
37
38 -(void)mouseDown:(NSEvent *)event ;
39 -(void)rightMouseDown:(NSEvent *)event ;
40 -(void)otherMouseDown:(NSEvent *)event ;
41 -(void)mouseUp:(NSEvent *)event ;
42 -(void)rightMouseUp:(NSEvent *)event ;
43 -(void)otherMouseUp:(NSEvent *)event ;
44 -(void)handleMouseEvent:(NSEvent *)event;
45
46 - (void)setImplementation: (wxWidgetImpl *) theImplementation;
47 - (wxWidgetImpl*) implementation;
48 - (BOOL) isFlipped;
49 - (BOOL) becomeFirstResponder;
50 - (BOOL) resignFirstResponder;
51
52 @end // wxNSView
53
54 void SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
55 {
56 UInt32 modifiers = [nsEvent modifierFlags] ;
57 wxPoint screenMouseLocation = wxFromNSPoint( NULL, [nsEvent locationInWindow]);
58
59 // these parameters are not given for all events
60 UInt32 button = [nsEvent buttonNumber];
61 UInt32 clickCount = [nsEvent clickCount];
62 UInt32 mouseChord = 0; // TODO does this exist for cocoa
63
64 wxevent.m_x = screenMouseLocation.x;
65 wxevent.m_y = screenMouseLocation.y;
66 wxevent.m_shiftDown = modifiers & NSShiftKeyMask;
67 wxevent.m_controlDown = modifiers & NSControlKeyMask;
68 wxevent.m_altDown = modifiers & NSAlternateKeyMask;
69 wxevent.m_metaDown = modifiers & NSCommandKeyMask;
70 wxevent.m_clickCount = clickCount;
71 wxevent.SetTimestamp( [nsEvent timestamp] * 1000.0 ) ;
72 /*
73 // a control click is interpreted as a right click
74 bool thisButtonIsFakeRight = false ;
75 if ( button == kEventMouseButtonPrimary && (modifiers & controlKey) )
76 {
77 button = kEventMouseButtonSecondary ;
78 thisButtonIsFakeRight = true ;
79 }
80
81 // otherwise we report double clicks by connecting a left click with a ctrl-left click
82 if ( clickCount > 1 && button != g_lastButton )
83 clickCount = 1 ;
84 // we must make sure that our synthetic 'right' button corresponds in
85 // mouse down, moved and mouse up, and does not deliver a right down and left up
86
87 if ( cEvent.GetKind() == kEventMouseDown )
88 {
89 g_lastButton = button ;
90 g_lastButtonWasFakeRight = thisButtonIsFakeRight ;
91 }
92
93 if ( button == 0 )
94 {
95 g_lastButton = 0 ;
96 g_lastButtonWasFakeRight = false ;
97 }
98 else if ( g_lastButton == kEventMouseButtonSecondary && g_lastButtonWasFakeRight )
99 button = g_lastButton ;
100
101 // Adjust the chord mask to remove the primary button and add the
102 // secondary button. It is possible that the secondary button is
103 // already pressed, e.g. on a mouse connected to a laptop, but this
104 // possibility is ignored here:
105 if( thisButtonIsFakeRight && ( mouseChord & 1U ) )
106 mouseChord = ((mouseChord & ~1U) | 2U);
107
108 if(mouseChord & 1U)
109 wxevent.m_leftDown = true ;
110 if(mouseChord & 2U)
111 wxevent.m_rightDown = true ;
112 if(mouseChord & 4U)
113 wxevent.m_middleDown = true ;
114
115 */
116 // translate into wx types
117 int eventType = [nsEvent type];
118 switch (eventType)
119 {
120 case NSLeftMouseDown :
121 case NSRightMouseDown :
122 case NSOtherMouseDown :
123 switch ( button )
124 {
125 case 0 :
126 wxevent.SetEventType( clickCount > 1 ? wxEVT_LEFT_DCLICK : wxEVT_LEFT_DOWN ) ;
127 break ;
128
129 case 1 :
130 wxevent.SetEventType( clickCount > 1 ? wxEVT_RIGHT_DCLICK : wxEVT_RIGHT_DOWN ) ;
131 break ;
132
133 case 2 :
134 wxevent.SetEventType( clickCount > 1 ? wxEVT_MIDDLE_DCLICK : wxEVT_MIDDLE_DOWN ) ;
135 break ;
136
137 default:
138 break ;
139 }
140 break ;
141
142 case NSLeftMouseUp :
143 case NSRightMouseUp :
144 case NSOtherMouseUp :
145 switch ( button )
146 {
147 case 0 :
148 wxevent.SetEventType( wxEVT_LEFT_UP ) ;
149 break ;
150
151 case 1 :
152 wxevent.SetEventType( wxEVT_RIGHT_UP ) ;
153 break ;
154
155 case 2 :
156 wxevent.SetEventType( wxEVT_MIDDLE_UP ) ;
157 break ;
158
159 default:
160 break ;
161 }
162 break ;
163
164 case NSScrollWheel :
165 {
166 wxevent.SetEventType( wxEVT_MOUSEWHEEL ) ;
167 /*
168 EventMouseWheelAxis axis = cEvent.GetParameter<EventMouseWheelAxis>(kEventParamMouseWheelAxis, typeMouseWheelAxis) ;
169 SInt32 delta = cEvent.GetParameter<SInt32>(kEventParamMouseWheelDelta, typeSInt32) ;
170 */
171 wxevent.m_wheelRotation = 10; // delta;
172 wxevent.m_wheelDelta = 1;
173 wxevent.m_linesPerAction = 1;
174 if ( 0 /* axis == kEventMouseWheelAxisX*/ )
175 wxevent.m_wheelAxis = 1;
176 }
177 break ;
178
179 case NSMouseEntered :
180 case NSMouseExited :
181 case NSLeftMouseDragged :
182 case NSRightMouseDragged :
183 case NSOtherMouseDragged :
184 case NSMouseMoved :
185 wxevent.SetEventType( wxEVT_MOTION ) ;
186 break;
187 default :
188 break ;
189 }
190 }
191
192 @implementation wxNSView
193
194 #define OSX_DEBUG_DRAWING 0
195
196 - (void)drawRect: (NSRect) rect
197 {
198 if ( impl )
199 {
200 CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
201 CGContextSaveGState( context );
202 #if OSX_DEBUG_DRAWING
203 CGContextBeginPath( context );
204 CGContextMoveToPoint(context, 0, 0);
205 NSRect bounds = [self bounds];
206 CGContextAddLineToPoint(context, 10, 0);
207 CGContextMoveToPoint(context, 0, 0);
208 CGContextAddLineToPoint(context, 0, 10);
209 CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
210 CGContextAddLineToPoint(context, bounds.size.width, bounds.size.height-10);
211 CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
212 CGContextAddLineToPoint(context, bounds.size.width-10, bounds.size.height);
213 CGContextClosePath( context );
214 CGContextStrokePath(context);
215 #endif
216
217 if ( [ self isFlipped ] == NO )
218 {
219 CGContextTranslateCTM( context, 0, [self bounds].size.height );
220 CGContextScaleCTM( context, 1, -1 );
221 }
222
223 wxRegion updateRgn;
224 const NSRect *rects;
225 int count ;
226
227 [self getRectsBeingDrawn:&rects count:&count];
228 for ( int i = 0 ; i < count ; ++i )
229 {
230 updateRgn.Union(wxFromNSRect(self, rects[i]) );
231 }
232
233 wxWindow* wxpeer = impl->GetWXPeer();
234 wxpeer->GetUpdateRegion() = updateRgn;
235 wxpeer->MacSetCGContextRef( context );
236
237 wxPaintEvent event;
238 event.SetTimestamp(0); // todo
239 event.SetEventObject(wxpeer);
240 wxpeer->HandleWindowEvent(event);
241
242 CGContextRestoreGState( context );
243 }
244 }
245
246 -(void)mouseDown:(NSEvent *)event
247 {
248 [self handleMouseEvent:event];
249 }
250
251 -(void)rightMouseDown:(NSEvent *)event
252 {
253 [self handleMouseEvent:event];
254 }
255
256 -(void)otherMouseDown:(NSEvent *)event
257 {
258 [self handleMouseEvent:event];
259 }
260
261 -(void)mouseUp:(NSEvent *)event
262 {
263 [self handleMouseEvent:event];
264 }
265
266 -(void)rightMouseUp:(NSEvent *)event
267 {
268 [self handleMouseEvent:event];
269 }
270
271 -(void)otherMouseUp:(NSEvent *)event
272 {
273 [self handleMouseEvent:event];
274 }
275
276 -(void)handleMouseEvent:(NSEvent *)event
277 {
278 NSPoint clickLocation;
279 clickLocation = [self convertPoint:[event locationInWindow] fromView:nil];
280 wxPoint pt = wxFromNSPoint( self, clickLocation );
281 wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
282 SetupMouseEvent( wxevent , event ) ;
283 wxevent.m_x = pt.x;
284 wxevent.m_y = pt.y;
285 impl->GetWXPeer()->HandleWindowEvent(wxevent);
286 }
287
288 - (void)setImplementation: (wxWidgetImpl *) theImplementation
289 {
290 impl = theImplementation;
291 }
292
293 - (wxWidgetImpl*) implementation
294 {
295 return impl;
296 }
297
298 - (BOOL) isFlipped
299 {
300 return YES;
301 }
302
303 - (BOOL) becomeFirstResponder
304 {
305 BOOL r = [super becomeFirstResponder];
306 if ( r )
307 {
308 }
309 return r;
310 }
311
312 - (BOOL) resignFirstResponder
313 {
314 BOOL r = [super resignFirstResponder];
315 if ( r )
316 {
317 }
318 return r;
319 }
320
321
322 @end // wxNSView
323
324 IMPLEMENT_DYNAMIC_CLASS( wxWidgetCocoaImpl , wxWidgetImpl )
325
326 wxWidgetCocoaImpl::wxWidgetCocoaImpl( wxWindowMac* peer , WXWidget w, bool isRootControl ) :
327 wxWidgetImpl( peer, isRootControl ), m_osxView(w)
328 {
329 }
330
331 wxWidgetCocoaImpl::wxWidgetCocoaImpl()
332 {
333 }
334
335 void wxWidgetCocoaImpl::Init()
336 {
337 m_osxView = NULL;
338 }
339
340 wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
341 {
342 if ( [m_osxView respondsToSelector:@selector(setImplementation:) ] )
343 [m_osxView setImplementation:NULL];
344 if ( !IsRootControl() )
345 {
346 NSView *sv = [m_osxView superview];
347 if ( sv != nil )
348 [m_osxView removeFromSuperview];
349 }
350 [m_osxView release];
351 }
352
353 bool wxWidgetCocoaImpl::IsVisible() const
354 {
355 return [m_osxView isHiddenOrHasHiddenAncestor] == NO;
356 }
357
358 void wxWidgetCocoaImpl::SetVisibility( bool visible )
359 {
360 [m_osxView setHidden:(visible ? NO:YES)];
361 }
362
363 void wxWidgetCocoaImpl::Raise()
364 {
365 }
366
367 void wxWidgetCocoaImpl::Lower()
368 {
369 }
370
371 void wxWidgetCocoaImpl::ScrollRect( const wxRect *rect, int dx, int dy )
372 {
373 }
374
375 void wxWidgetCocoaImpl::Move(int x, int y, int width, int height)
376 {
377 NSRect r = wxToNSRect( [m_osxView superview], wxRect(x,y,width, height) );
378 [m_osxView setFrame:r];
379 }
380
381 void wxWidgetCocoaImpl::GetPosition( int &x, int &y ) const
382 {
383 wxRect r = wxFromNSRect( [m_osxView superview], [m_osxView frame] );
384 x = r.GetLeft();
385 y = r.GetTop();
386 }
387
388 void wxWidgetCocoaImpl::GetSize( int &width, int &height ) const
389 {
390 NSRect rect = [m_osxView frame];
391 width = rect.size.width;
392 height = rect.size.height;
393 }
394
395 void wxWidgetCocoaImpl::GetContentArea( int&left, int &top, int &width, int &height ) const
396 {
397 left = top = 0;
398 GetSize( width, height );
399 }
400
401 void wxWidgetCocoaImpl::SetNeedsDisplay( const wxRect* where )
402 {
403 if ( where )
404 [m_osxView setNeedsDisplayInRect:wxToNSRect(m_osxView, *where )];
405 else
406 [m_osxView setNeedsDisplay:YES];
407 }
408
409 bool wxWidgetCocoaImpl::GetNeedsDisplay() const
410 {
411 return [m_osxView needsDisplay];
412 }
413
414 bool wxWidgetCocoaImpl::CanFocus() const
415 {
416 return [m_osxView canBecomeKeyView] == YES;
417 }
418
419 bool wxWidgetCocoaImpl::HasFocus() const
420 {
421 return ( [[m_osxView window] firstResponder] == m_osxView );
422 }
423
424 bool wxWidgetCocoaImpl::SetFocus()
425 {
426 if ( [m_osxView canBecomeKeyView] == NO )
427 return false;
428
429 [[m_osxView window] makeFirstResponder: m_osxView] ;
430 return true;
431 }
432
433
434 void wxWidgetCocoaImpl::RemoveFromParent()
435 {
436 [m_osxView removeFromSuperview];
437 }
438
439 void wxWidgetCocoaImpl::Embed( wxWidgetImpl *parent )
440 {
441 NSView* container = parent->GetWXWidget() ;
442 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
443 [container addSubview:m_osxView];
444 }
445
446 void wxWidgetCocoaImpl::SetBackgroundColour( const wxColour &WXUNUSED(col) )
447 {
448 // m_osxView.backgroundColor = [[UIColor alloc] initWithCGColor:col.GetCGColor()];
449 }
450
451 void wxWidgetCocoaImpl::SetLabel( const wxString& title, wxFontEncoding encoding )
452 {
453 if ( [m_osxView respondsToSelector:@selector(setTitle:) ] )
454 {
455 wxCFStringRef cf( title , m_wxPeer->GetFont().GetEncoding() );
456 [m_osxView setTitle:cf.AsNSString()];
457 }
458 }
459
460
461 void wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
462 {
463 NSPoint p = wxToNSPoint( from->GetWXWidget(), *pt );
464 p = [from->GetWXWidget() convertPoint:p toView:to->GetWXWidget() ];
465 *pt = wxFromNSPoint( to->GetWXWidget(), p );
466 }
467
468 wxInt32 wxWidgetCocoaImpl::GetValue() const
469 {
470 return [(NSControl*)m_osxView intValue];
471 }
472
473 void wxWidgetCocoaImpl::SetValue( wxInt32 v )
474 {
475 if ( [m_osxView respondsToSelector:@selector(setIntValue:)] )
476 {
477 [m_osxView setIntValue:v];
478 }
479 else if ( [m_osxView respondsToSelector:@selector(setFloatValue:)] )
480 {
481 [m_osxView setFloatValue:(double)v];
482 }
483 else if ( [m_osxView respondsToSelector:@selector(setDoubleValue:)] )
484 {
485 [m_osxView setDoubleValue:(double)v];
486 }
487 }
488
489 void wxWidgetCocoaImpl::SetMinimum( wxInt32 v )
490 {
491 if ( [m_osxView respondsToSelector:@selector(setMinValue:)] )
492 {
493 [m_osxView setMinValue:(double)v];
494 }
495 }
496
497 void wxWidgetCocoaImpl::SetMaximum( wxInt32 v )
498 {
499 if ( [m_osxView respondsToSelector:@selector(setMaxValue:)] )
500 {
501 [m_osxView setMaxValue:(double)v];
502 }
503 }
504
505 void wxWidgetCocoaImpl::SetBitmap( const wxBitmap& bitmap )
506 {
507 if ( [m_osxView respondsToSelector:@selector(setImage:)] )
508 {
509 [m_osxView setImage:bitmap.GetNSImage()];
510 }
511 }
512
513 void wxWidgetCocoaImpl::SetupTabs( const wxNotebook& notebook)
514 {
515 // implementation in subclass
516 }
517
518 void wxWidgetCocoaImpl::GetBestRect( wxRect *r ) const
519 {
520 r->x = r->y = r->width = r->height = 0;
521 // if ( [m_osxView isKindOfClass:[NSControl class]] )
522 if ( [m_osxView respondsToSelector:@selector(sizeToFit)] )
523 {
524 NSRect former = [m_osxView frame];
525 [m_osxView sizeToFit];
526 NSRect best = [m_osxView frame];
527 [m_osxView setFrame:former];
528 r->width = best.size.width;
529 r->height = best.size.height;
530 }
531 }
532
533 bool wxWidgetCocoaImpl::IsEnabled() const
534 {
535 if ( [m_osxView respondsToSelector:@selector(isEnabled) ] )
536 return [m_osxView isEnabled];
537 return true;
538 }
539
540 void wxWidgetCocoaImpl::Enable( bool enable )
541 {
542 if ( [m_osxView respondsToSelector:@selector(setEnabled:) ] )
543 [m_osxView setEnabled:enable];
544 }
545
546 void wxWidgetCocoaImpl::PulseGauge()
547 {
548 }
549
550 void wxWidgetCocoaImpl::SetScrollThumb( wxInt32 val, wxInt32 view )
551 {
552 }
553
554 void wxWidgetCocoaImpl::SetControlSize( wxWindowVariant variant )
555 {
556 NSControlSize size = NSRegularControlSize;
557
558 switch ( variant )
559 {
560 case wxWINDOW_VARIANT_NORMAL :
561 size = NSRegularControlSize;
562 break ;
563
564 case wxWINDOW_VARIANT_SMALL :
565 size = NSSmallControlSize;
566 break ;
567
568 case wxWINDOW_VARIANT_MINI :
569 size = NSMiniControlSize;
570 break ;
571
572 case wxWINDOW_VARIANT_LARGE :
573 size = NSRegularControlSize;
574 break ;
575
576 default:
577 wxFAIL_MSG(_T("unexpected window variant"));
578 break ;
579 }
580 if ( [m_osxView respondsToSelector:@selector(setControlSize:)] )
581 [m_osxView setControlSize:size];
582 }
583
584 //
585 // Factory methods
586 //
587
588 wxWidgetImpl* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer, wxWindowMac* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
589 long style, long extraStyle)
590 {
591 NSView* sv = (wxpeer->GetParent()->GetHandle() );
592
593 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
594 wxNSView* v = [[wxNSView alloc] initWithFrame:r];
595 [sv addSubview:v];
596 wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v );
597 [v setImplementation:c];
598 return c;
599 }
600
601 wxWidgetImpl* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
602 {
603 NSWindow* tlw = now->GetWXWindow();
604 wxNSView* v = [[wxNSView alloc] initWithFrame:[[tlw contentView] frame]];
605 wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( now, v, true );
606 [v setImplementation:c];
607 [tlw setContentView:v];
608 return c;
609 }