// Author: Stefan Csomor
// Modified by:
// Created: 2008-06-20
-// RCS-ID: $Id$
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/log.h"
#include "wx/textctrl.h"
#include "wx/combobox.h"
+ #include "wx/radiobut.h"
#endif
#ifdef __WXMAC__
// Get the window with the focus
-NSView* GetViewFromResponder( NSResponder* responder )
+NSView* wxOSXGetViewFromResponder( NSResponder* responder )
{
NSView* view = nil;
if ( [responder isKindOfClass:[NSTextView class]] )
{
NSView* focusedView = nil;
if ( keyWindow != nil )
- focusedView = GetViewFromResponder([keyWindow firstResponder]);
+ focusedView = wxOSXGetViewFromResponder([keyWindow firstResponder]);
return focusedView;
}
WXWidget wxWidgetImpl::FindFocus()
{
- return GetFocusedViewInWindow( [NSApp keyWindow] );
+ return GetFocusedViewInWindow( [NSApp keyWindow] );;
}
+wxWidgetImpl* wxWidgetImpl::FindBestFromWXWidget(WXWidget control)
+{
+ wxWidgetImpl* impl = FindFromWXWidget(control);
+
+ // NSScrollViews can have their subviews like NSClipView
+ // therefore check and use the NSScrollView peer in that case
+ if ( impl == NULL && [[control superview] isKindOfClass:[NSScrollView class]])
+ impl = FindFromWXWidget([control superview]);
+
+ return impl;
+}
+
+
NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
{
int x, y, w, h ;
@end // wxNSView
+@interface wxNSView(TextInput) <NSTextInputClient>
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange;
+- (void)doCommandBySelector:(SEL)aSelector;
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange;
+- (void)unmarkText;
+- (NSRange)selectedRange;
+- (NSRange)markedRange;
+- (BOOL)hasMarkedText;
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSArray*)validAttributesForMarkedText;
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint;
+
+@end
+
@interface NSView(PossibleMethods)
- (void)setTitle:(NSString *)aString;
- (void)setStringValue:(NSString *)aString;
wxevent.m_wheelDelta = 10;
wxevent.m_linesPerAction = 1;
+ wxevent.m_columnsPerAction = 1;
if ( fabs(deltaX) > fabs(deltaY) )
{
+ // wx conventions for horizontal are inverted from vertical (originating from native msw behavior)
+ // right and up are positive values, left and down are negative values, while on OSX right and down
+ // are negative and left and up are positive.
wxevent.m_wheelAxis = wxMOUSE_WHEEL_HORIZONTAL;
- wxevent.m_wheelRotation = (int)deltaX;
+ wxevent.m_wheelRotation = -(int)deltaX;
}
else
{
@end // wxNSView
+// We need to adopt NSTextInputClient protocol in order to interpretKeyEvents: to work.
+// Currently, only insertText:(replacementRange:) is
+// implemented here, and the rest of the methods are stubs.
+// It is hoped that someday IME-related functionality is implemented in
+// wxWidgets and the methods of this protocol are fully working.
+
+@implementation wxNSView(TextInput)
+
+void wxOSX_insertText(NSView* self, SEL _cmd, NSString* text);
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+ wxOSX_insertText(self, @selector(insertText:), aString);
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ // these are already caught in the keyEvent handler
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+}
+
+- (void)unmarkText
+{
+}
+
+- (NSRange)selectedRange
+{
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (NSRange)markedRange
+{
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (BOOL)hasMarkedText
+{
+ return NO;
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ return nil;
+}
+
+- (NSArray*)validAttributesForMarkedText
+{
+ return nil;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ return NSMakeRect(0, 0, 0, 0);
+}
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+ return NSNotFound;
+}
+
+@end // wxNSView(TextInput)
+
+
//
// event handlers
//
return result != wxDragNone;
}
-typedef void (*wxOSX_TextEventHandlerPtr)(NSView* self, SEL _cmd, NSString *event);
-typedef void (*wxOSX_EventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
-typedef BOOL (*wxOSX_PerformKeyEventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
-typedef BOOL (*wxOSX_FocusHandlerPtr)(NSView* self, SEL _cmd);
-
void wxWidgetCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
{
// we are getting moved events for all windows in the hierarchy, not something wx expects
// therefore we only handle it for the deepest child in the hierarchy
- if ( 1 /* [event type] == NSMouseMoved */ )
+ if ( [event type] == NSMouseMoved )
{
NSView* hitview = [[[slf window] contentView] hitTest:[event locationInWindow]];
if ( hitview == NULL || hitview != slf)
if ( !DoHandleMouseEvent(event) )
{
// for plain NSView mouse events would propagate to parents otherwise
- if (!IsUserPane())
+ // scrollwheel events have to be propagated if not handled in all cases
+ if (!IsUserPane() || [event type] == NSScrollWheel )
{
wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
superimpl(slf, (SEL)_cmd, event);
{
wxEvtHandler * const handler = m_wxPeer->GetEventHandler();
- wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
+ wxCommandEvent command_event( wxEVT_MENU, command );
command_event.SetEventObject( wxevent.GetEventObject() );
handled = handler->ProcessEvent( command_event );
if ( !handled )
{
// accelerators can also be used with buttons, try them too
- command_event.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
+ command_event.SetEventType(wxEVT_BUTTON);
handled = handler->ProcessEvent( command_event );
}
}
{
wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
BOOL r = superimpl(slf, (SEL)_cmd);
- // get the current focus after running resignFirstResponder
- // note that this value isn't reliable, it might return the same view that
- // is resigning
- NSView* otherView = FindFocus();
- wxWidgetImpl* otherWindow = FindFromWXWidget(otherView);
+
+ NSResponder * responder = wxNonOwnedWindowCocoaImpl::GetNextFirstResponder();
+ NSView* otherView = wxOSXGetViewFromResponder(responder);
- // It doesn't make sense to notify about the loss of focus if we're not
- // really losing it and the window which has just gained focus is the same
- // one as this window itself. Of course, this should never happen in the
- // first place but somehow it does in wxGrid code and without this check we
- // enter into an infinite recursion, see #12267.
+ wxWidgetImpl* otherWindow = FindBestFromWXWidget(otherView);
+
+ // It doesn't make sense to notify about the loss of focus if it's the same
+ // control in the end, and just a different subview
if ( otherWindow == this )
return r;
-
+
// NSTextViews have an editor as true responder, therefore the might get the
// resign notification if their editor takes over, don't trigger any event then
if ( r && !m_hasEditor)
[m_osxView setHidden:(visible ? NO:YES)];
}
+double wxWidgetCocoaImpl::GetContentScaleFactor() const
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+ NSWindow* tlw = [m_osxView window];
+ if ( [ tlw respondsToSelector:@selector(backingScaleFactor) ] )
+ return [tlw backingScaleFactor];
+ else
+#endif
+ return 1.0;
+}
+
// ----------------------------------------------------------------------------
// window animation stuff
// ----------------------------------------------------------------------------
wxUnusedVar(progress);
m_win->SendSizeEvent();
- m_win->MacOnInternalSize();
}
- (void)animationDidEnd:(NSAnimation*)animation
// refresh it once again after the end to ensure that everything is in
// place
win->SendSizeEvent();
- win->MacOnInternalSize();
}
[anim setDelegate:nil];
if ([c respondsToSelector:@selector(setAction:)])
{
[c setTarget: c];
- [c setAction: @selector(controlAction:)];
+ if ( dynamic_cast<wxRadioButton*>(GetWXPeer()) )
+ {
+ // everything already set up
+ }
+ else
+ [c setAction: @selector(controlAction:)];
+
if ([c respondsToSelector:@selector(setDoubleAction:)])
{
[c setDoubleAction: @selector(controlDoubleAction:)];
}
NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited|NSTrackingCursorUpdate|NSTrackingMouseMoved|NSTrackingActiveAlways|NSTrackingInVisibleRect;
- NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil];
+ NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil];
[m_osxView addTrackingArea: area];
[area release];
}
bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text)
{
- wxKeyEvent wxevent(wxEVT_CHAR);
- SetupKeyEvent( wxevent, event, text );
+ bool result = false;
+
+ for (NSUInteger i = 0; i < [text length]; ++i)
+ {
+ wxKeyEvent wxevent(wxEVT_CHAR);
+ unichar c = [text characterAtIndex:i];
+ SetupKeyEvent( wxevent, event, [NSString stringWithCharacters:&c length:1]);
- return GetWXPeer()->OSXHandleKeyEvent(wxevent);
+ result = GetWXPeer()->OSXHandleKeyEvent(wxevent) || result;
+ }
+
+ return result;
}
bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event)