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