- (void)setImagePosition:(NSCellImagePosition)aPosition;
@end
+// in case we want to use the native tooltip callbacks
+
+#if 0
+
+@interface NSView(wxToolTip)
+- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)userData;
+@end
+
+@implementation NSView(wxToolTip)
+
+- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)userData {
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( view );
+ if (impl == NULL)
+ return nil;
+
+ return @"Tag";
+}
+@end
+
+#endif
+
+// The following code is a combination of the code listed here:
+// http://lists.apple.com/archives/cocoa-dev/2008/Apr/msg01582.html
+// (which can't be used because KLGetCurrentKeyboardLayout etc aren't 64-bit)
+// and the code here:
+// http://inquisitivecocoa.com/category/objective-c/
+@interface NSEvent (OsGuiUtilsAdditions)
+- (NSString*) charactersIgnoringModifiersIncludingShift;
+@end
+
+@implementation NSEvent (OsGuiUtilsAdditions)
+- (NSString*) charactersIgnoringModifiersIncludingShift {
+ // First try -charactersIgnoringModifiers and look for keys which UCKeyTranslate translates
+ // differently than AppKit.
+ NSString* c = [self charactersIgnoringModifiers];
+ if ([c length] == 1) {
+ unichar codepoint = [c characterAtIndex:0];
+ if ((codepoint >= 0xF700 && codepoint <= 0xF8FF) || codepoint == 0x7F) {
+ return c;
+ }
+ }
+ // This is not a "special" key, so ask UCKeyTranslate to give us the character with no
+ // modifiers attached. Actually, that's not quite accurate; we attach the Command modifier
+ // which hints the OS to use Latin characters where possible, which is generally what we want.
+ NSString* result = @"";
+ TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+ CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
+ CFRelease(currentKeyboard);
+ if (uchr == NULL) {
+ // this can happen for some non-U.S. input methods (eg. Romaji or Hiragana)
+ return c;
+ }
+ const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
+ if (keyboardLayout) {
+ UInt32 deadKeyState = 0;
+ UniCharCount maxStringLength = 255;
+ UniCharCount actualStringLength = 0;
+ UniChar unicodeString[maxStringLength];
+
+ OSStatus status = UCKeyTranslate(keyboardLayout,
+ [self keyCode],
+ kUCKeyActionDown,
+ cmdKey >> 8, // force the Command key to "on"
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysMask,
+ &deadKeyState,
+ maxStringLength,
+ &actualStringLength,
+ unicodeString);
+
+ if(status == noErr)
+ result = [NSString stringWithCharacters:unicodeString length:(NSInteger)actualStringLength];
+ }
+ return result;
+}
+@end
+
long wxOSXTranslateCocoaKey( NSEvent* event, int eventType )
{
long retval = 0;
if ([event type] != NSFlagsChanged)
{
- NSString* s = [event charactersIgnoringModifiers];
+ NSString* s = [event charactersIgnoringModifiersIncludingShift];
// backspace char reports as delete w/modifiers for some reason
if ([s length] == 1)
{
int intchar = [s characterAtIndex: 0];
if ( intchar >= NSF1FunctionKey && intchar <= NSF24FunctionKey )
retval = WXK_F1 + (intchar - NSF1FunctionKey );
+ else if ( intchar > 0 && intchar < 32 )
+ retval = intchar;
break;
}
}
wxString chars;
if ( eventType != NSFlagsChanged )
{
- NSString* nschars = [[nsEvent charactersIgnoringModifiers] uppercaseString];
+ NSString* nschars = [[nsEvent charactersIgnoringModifiersIncludingShift] uppercaseString];
if ( charString )
{
// if charString is set, it did not come from key up / key down
{
wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
superimpl(slf, (SEL)_cmd, event);
+
+ // super of built-ins keeps the mouse up, as wx expects this event, we have to synthesize it
+
+ if ( [ event type] == NSLeftMouseDown )
+ {
+ wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
+ SetupMouseEvent(wxevent , event) ;
+ wxevent.SetEventType(wxEVT_LEFT_UP);
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+ }
}
}
}
wxEvtHandler * const handler = m_wxPeer->GetEventHandler();
wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
+ command_event.SetEventObject( wxevent.GetEventObject() );
handled = handler->ProcessEvent( command_event );
if ( !handled )
updateRgn.Offset( wxpeer->MacGetLeftBorderSize() , wxpeer->MacGetTopBorderSize() );
}
- if ( wxpeer->MacGetTopLevelWindow()->GetWindowStyle() & wxFRAME_SHAPED )
+ // Restrict the update region to the shape of the window, if any, and also
+ // remember the region that we need to clear later.
+ wxNonOwnedWindow* const tlwParent = wxpeer->MacGetTopLevelWindow();
+ const bool isTopLevel = tlwParent == wxpeer;
+ wxRegion clearRgn;
+ if ( tlwParent->GetWindowStyle() & wxFRAME_SHAPED )
{
+ if ( isTopLevel )
+ clearRgn = updateRgn;
+
int xoffset = 0, yoffset = 0;
- wxRegion rgn = wxpeer->MacGetTopLevelWindow()->GetShape();
+ wxRegion rgn = tlwParent->GetShape();
wxpeer->MacRootWindowToWindow( &xoffset, &yoffset );
rgn.Offset( xoffset, yoffset );
updateRgn.Intersect(rgn);
+
+ if ( isTopLevel )
+ {
+ // Exclude the window shape from the region to be cleared below.
+ rgn.Xor(wxpeer->GetSize());
+ clearRgn.Intersect(rgn);
+ }
}
wxpeer->GetUpdateRegion() = updateRgn;
CGContextTranslateCTM( context, 0, [m_osxView bounds].size.height );
CGContextScaleCTM( context, 1, -1 );
}
+
+ if ( isTopLevel )
+ {
+ // We also need to explicitly draw the part of the top level window
+ // outside of its region with transparent colour to ensure that it is
+ // really transparent.
+ if ( clearRgn.IsOk() )
+ {
+ wxMacCGContextStateSaver saveState(context);
+ wxWindowDC dc(wxpeer);
+ dc.SetBackground(wxBrush(wxTransparentColour));
+ dc.SetDeviceClippingRegion(clearRgn);
+ dc.Clear();
+ }
+
+#if wxUSE_GRAPHICS_CONTEXT
+ // If the window shape is defined by a path, stroke the path to show
+ // the window border.
+ const wxGraphicsPath& path = tlwParent->GetShapePath();
+ if ( !path.IsNull() )
+ {
+ CGContextSetLineWidth(context, 1);
+ CGContextSetStrokeColorWithColor(context, wxLIGHT_GREY->GetCGColor());
+ CGContextAddPath(context, (CGPathRef) path.GetNativePath());
+ CGContextStrokePath(context);
+ }
+#endif // wxUSE_GRAPHICS_CONTEXT
+ }
+
wxpeer->MacPaintChildrenBorders();
wxpeer->MacSetCGContextRef( NULL );
CGContextRestoreGState( context );
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];
return ShowViewOrWindowWithEffect(m_wxPeer, show, effect, timeout);
}
+/* note that the drawing order between siblings is not defined under 10.4 */
+/* only starting from 10.5 the subview order is respected */
+
+/* NSComparisonResult is typedef'd as an enum pre-Leopard but typedef'd as
+ * NSInteger post-Leopard. Pre-Leopard the Cocoa toolkit expects a function
+ * returning int and not NSComparisonResult. Post-Leopard the Cocoa toolkit
+ * expects a function returning the new non-enum NSComparsionResult.
+ * Hence we create a typedef named CocoaWindowCompareFunctionResult.
+ */
+#if defined(NSINTEGER_DEFINED)
+typedef NSComparisonResult CocoaWindowCompareFunctionResult;
+#else
+typedef int CocoaWindowCompareFunctionResult;
+#endif
+
+class CocoaWindowCompareContext
+{
+ wxDECLARE_NO_COPY_CLASS(CocoaWindowCompareContext);
+public:
+ CocoaWindowCompareContext(); // Not implemented
+ CocoaWindowCompareContext(NSView *target, NSArray *subviews)
+ {
+ m_target = target;
+ // Cocoa sorts subviews in-place.. make a copy
+ m_subviews = [subviews copy];
+ }
+
+ ~CocoaWindowCompareContext()
+ { // release the copy
+ [m_subviews release];
+ }
+ NSView* target()
+ { return m_target; }
+
+ NSArray* subviews()
+ { return m_subviews; }
+
+ /* Helper function that returns the comparison based off of the original ordering */
+ CocoaWindowCompareFunctionResult CompareUsingOriginalOrdering(id first, id second)
+ {
+ NSUInteger firstI = [m_subviews indexOfObjectIdenticalTo:first];
+ NSUInteger secondI = [m_subviews indexOfObjectIdenticalTo:second];
+ // NOTE: If either firstI or secondI is NSNotFound then it will be NSIntegerMax and thus will
+ // likely compare higher than the other view which is reasonable considering the only way that
+ // can happen is if the subview was added after our call to subviews but before the call to
+ // sortSubviewsUsingFunction:context:. Thus we don't bother checking. Particularly because
+ // that case should never occur anyway because that would imply a multi-threaded GUI call
+ // which is a big no-no with Cocoa.
+
+ // Subviews are ordered from back to front meaning one that is already lower will have an lower index.
+ NSComparisonResult result = (firstI < secondI)
+ ? NSOrderedAscending /* -1 */
+ : (firstI > secondI)
+ ? NSOrderedDescending /* 1 */
+ : NSOrderedSame /* 0 */;
+
+ return result;
+ }
+private:
+ /* The subview we are trying to Raise or Lower */
+ NSView *m_target;
+ /* A copy of the original array of subviews */
+ NSArray *m_subviews;
+};
+
+/* Causes Cocoa to raise the target view to the top of the Z-Order by telling the sort function that
+ * the target view is always higher than every other view. When comparing two views neither of
+ * which is the target, it returns the correct response based on the original ordering
+ */
+static CocoaWindowCompareFunctionResult CocoaRaiseWindowCompareFunction(id first, id second, void *ctx)
+{
+ CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
+ // first should be ordered higher
+ if(first==compareContext->target())
+ return NSOrderedDescending;
+ // second should be ordered higher
+ if(second==compareContext->target())
+ return NSOrderedAscending;
+ return compareContext->CompareUsingOriginalOrdering(first,second);
+}
+
void wxWidgetCocoaImpl::Raise()
{
- // Not implemented
+ NSView* nsview = m_osxView;
+
+ NSView *superview = [nsview superview];
+ CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
+
+ [superview sortSubviewsUsingFunction:
+ CocoaRaiseWindowCompareFunction
+ context: &compareContext];
+
+}
+
+/* Causes Cocoa to lower the target view to the bottom of the Z-Order by telling the sort function that
+ * the target view is always lower than every other view. When comparing two views neither of
+ * which is the target, it returns the correct response based on the original ordering
+ */
+static CocoaWindowCompareFunctionResult CocoaLowerWindowCompareFunction(id first, id second, void *ctx)
+{
+ CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
+ // first should be ordered lower
+ if(first==compareContext->target())
+ return NSOrderedAscending;
+ // second should be ordered lower
+ if(second==compareContext->target())
+ return NSOrderedDescending;
+ return compareContext->CompareUsingOriginalOrdering(first,second);
}
void wxWidgetCocoaImpl::Lower()
{
- // Not implemented
+ NSView* nsview = m_osxView;
+
+ NSView *superview = [nsview superview];
+ CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
+
+ [superview sortSubviewsUsingFunction:
+ CocoaLowerWindowCompareFunction
+ context: &compareContext];
}
void wxWidgetCocoaImpl::ScrollRect( const wxRect *WXUNUSED(rect), int WXUNUSED(dx), int WXUNUSED(dy) )
if ( !CanFocus() )
return false;
- [[m_osxView window] makeKeyAndOrderFront:nil] ;
+ // TODO remove if no issues arise: should not raise the window, only assign focus
+ //[[m_osxView window] makeKeyAndOrderFront:nil] ;
[[m_osxView window] makeFirstResponder: m_osxView] ;
return true;
}
{
if ( [m_osxView respondsToSelector:@selector(setImage:)] )
{
- [m_osxView setImage:bitmap.GetNSImage()];
+ if (bitmap.IsOk())
+ [m_osxView setImage:bitmap.GetNSImage()];
+ else
+ [m_osxView setImage:nil];
+
[m_osxView setNeedsDisplay:YES];
}
}
alpha:(CGFloat) (col.Alpha() / 255.0)]];
}
+NSToolTipTag tt = 0;
+
void wxWidgetCocoaImpl::SetToolTip(wxToolTip* tooltip)
{
if (tooltip)
{
+ /*
+ if ( tt != 0 )
+ {
+ [m_osxView removeToolTip:tt];
+ tt = 0;
+ }
+ */
wxCFStringRef cf( tooltip->GetTip() , m_wxPeer->GetFont().GetEncoding() );
[m_osxView setToolTip: cf.AsNSString()];
+ // tt = [m_osxView addToolTipRect:[m_osxView bounds] owner:m_osxView userData:nil];
}
else
- [m_osxView setToolTip: nil];
+ {
+ if ( tt != 0 )
+ {
+ [m_osxView removeToolTip:tt];
+ tt = 0;
+ }
+ }
}
{
wxKeyEvent wxevent(wxEVT_KEY_DOWN);
SetupKeyEvent( wxevent, event );
+
+ // Generate wxEVT_CHAR_HOOK before sending any other events but only when
+ // the key is pressed, not when it's released (the type of wxevent is
+ // changed by SetupKeyEvent() so it can be wxEVT_KEY_UP too by now).
+ if ( wxevent.GetEventType() == wxEVT_KEY_DOWN )
+ {
+ wxKeyEvent eventHook(wxEVT_CHAR_HOOK, wxevent);
+ if ( GetWXPeer()->OSXHandleKeyEvent(eventHook)
+ && !eventHook.IsNextEventAllowed() )
+ return true;
+ }
+
bool result = GetWXPeer()->OSXHandleKeyEvent(wxevent);
// this will fire higher level events, like insertText, to help