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