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