diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index 3a5a0c8e78..60c4c1a8ca 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -50,31 +50,13 @@ QT_USE_NAMESPACE -static NSButton *macCreateButton(const char *text, NSView *superview) -{ - static const NSRect buttonFrameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } }; - - NSButton *button = [[NSButton alloc] initWithFrame:buttonFrameRect]; - [button setButtonType:NSMomentaryLightButton]; - [button setBezelStyle:NSRoundedBezelStyle]; - [button setTitle:(NSString*)(CFStringRef)QCFString( - QPlatformTheme::removeMnemonics(QCoreApplication::translate("QPlatformTheme", text)))]; - [[button cell] setFont:[NSFont systemFontOfSize: - [NSFont systemFontSizeForControlSize:NSRegularControlSize]]]; - [superview addSubview:button]; - return button; -} - -@class QT_MANGLE_NAMESPACE(QNSColorPanelDelegate); - -@interface QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) : NSObject +@interface QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) : NSObject { @public NSColorPanel *mColorPanel; QCocoaColorDialogHelper *mHelper; NSView *mStolenContentView; - NSButton *mOkButton; - NSButton *mCancelButton; + QNSPanelContentsWrapper *mPanelButtons; QColor mQtColor; NSInteger mResultCode; BOOL mDialogIsExecuting; @@ -82,7 +64,6 @@ static NSButton *macCreateButton(const char *text, NSView *superview) BOOL mClosingDueToKnownButton; }; - (void)restoreOriginalContentView; -- (void)relayout; - (void)updateQtColor; - (void)finishOffWithCode:(NSInteger)code; @end @@ -97,8 +78,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); mColorPanel = [NSColorPanel sharedColorPanel]; mHelper = 0; mStolenContentView = 0; - mOkButton = 0; - mCancelButton = 0; + mPanelButtons = nil; mResultCode = NSCancelButton; mDialogIsExecuting = false; mResultSet = false; @@ -142,23 +122,10 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); [mColorPanel setContentView:0]; // create a new content view and add the stolen one as a subview - NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } }; - NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect]; - [ourContentView addSubview:mStolenContentView]; - - // create OK and Cancel buttons and add these as subviews - mOkButton = macCreateButton("&OK", ourContentView); - mCancelButton = macCreateButton("Cancel", ourContentView); - - [mColorPanel setContentView:ourContentView]; - [mColorPanel setDefaultButtonCell:[mOkButton cell]]; - [self relayout]; - - [mOkButton setAction:@selector(onOkClicked)]; - [mOkButton setTarget:self]; - - [mCancelButton setAction:@selector(onCancelClicked)]; - [mCancelButton setTarget:self]; + mPanelButtons = [[QNSPanelContentsWrapper alloc] initWithPanelDelegate:self]; + [mPanelButtons addSubview:mStolenContentView]; + mColorPanel.contentView = mPanelButtons; + mColorPanel.defaultButtonCell = mPanelButtons.okButton.cell; } } @@ -167,12 +134,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); [mColorPanel close]; } -- (void)windowDidResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - [self relayout]; -} - - (void)colorChanged:(NSNotification *)notification { Q_UNUSED(notification); @@ -182,7 +143,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); - (void)windowWillClose:(NSNotification *)notification { Q_UNUSED(notification); - if (mCancelButton && mHelper && !mClosingDueToKnownButton) { + if (mPanelButtons && mHelper && !mClosingDueToKnownButton) { mClosingDueToKnownButton = true; // prevent repeating emit emit mHelper->reject(); } @@ -191,68 +152,16 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); - (void)restoreOriginalContentView { if (mStolenContentView) { - NSView *ourContentView = [mColorPanel contentView]; - // return stolen stuff to its rightful owner [mStolenContentView removeFromSuperview]; [mColorPanel setContentView:mStolenContentView]; - [mOkButton release]; - [mCancelButton release]; - [ourContentView release]; - mOkButton = 0; - mCancelButton = 0; - mStolenContentView = 0; + [mStolenContentView release]; + mStolenContentView = nil; + [mPanelButtons release]; + mPanelButtons = nil; } } -- (void)relayout -{ - if (!mOkButton) - return; - - NSRect rect = [[mStolenContentView superview] frame]; - - // should a priori be kept in sync with qfontdialog_mac.mm - const CGFloat ButtonMinWidth = 78.0; // 84.0 for Carbon - const CGFloat ButtonMinHeight = 32.0; - const CGFloat ButtonSpacing = 0.0; - const CGFloat ButtonTopMargin = 0.0; - const CGFloat ButtonBottomMargin = 7.0; - const CGFloat ButtonSideMargin = 9.0; - - [mOkButton sizeToFit]; - NSSize okSizeHint = [mOkButton frame].size; - - [mCancelButton sizeToFit]; - NSSize cancelSizeHint = [mCancelButton frame].size; - - const CGFloat ButtonWidth = qMin(qMax(ButtonMinWidth, - qMax(okSizeHint.width, cancelSizeHint.width)), - CGFloat((rect.size.width - 2.0 * ButtonSideMargin - ButtonSpacing) * 0.5)); - const CGFloat ButtonHeight = qMax(ButtonMinHeight, - qMax(okSizeHint.height, cancelSizeHint.height)); - - NSRect okRect = { { rect.size.width - ButtonSideMargin - ButtonWidth, - ButtonBottomMargin }, - { ButtonWidth, ButtonHeight } }; - [mOkButton setFrame:okRect]; - [mOkButton setNeedsDisplay:YES]; - - NSRect cancelRect = { { okRect.origin.x - ButtonSpacing - ButtonWidth, - ButtonBottomMargin }, - { ButtonWidth, ButtonHeight } }; - [mCancelButton setFrame:cancelRect]; - [mCancelButton setNeedsDisplay:YES]; - - const CGFloat Y = ButtonBottomMargin + ButtonHeight + ButtonTopMargin; - NSRect stolenCVRect = { { 0.0, Y }, - { rect.size.width, rect.size.height - Y } }; - [mStolenContentView setFrame:stolenCVRect]; - [mStolenContentView setNeedsDisplay:YES]; - - [[mStolenContentView superview] setNeedsDisplay:YES]; -} - - (void)onOkClicked { mClosingDueToKnownButton = true; @@ -263,7 +172,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); - (void)onCancelClicked { - if (mOkButton) { + if (mPanelButtons) { mClosingDueToKnownButton = true; [mColorPanel close]; mQtColor = QColor(); @@ -335,7 +244,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); - (BOOL)windowShouldClose:(id)window { Q_UNUSED(window); - if (!mOkButton) + if (!mPanelButtons) [self updateQtColor]; if (mDialogIsExecuting) { [self finishOffWithCode:NSCancelButton]; diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm index 0be931b54f..e565f3b5b1 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm @@ -58,33 +58,6 @@ typedef float CGFloat; // Should only not be defined on 32-bit platforms QT_USE_NAMESPACE -// should a priori be kept in sync with qcolordialog_mac.mm -const CGFloat ButtonMinWidth = 78.0; -const CGFloat ButtonMinHeight = 32.0; -const CGFloat ButtonSpacing = 0.0; -const CGFloat ButtonTopMargin = 0.0; -const CGFloat ButtonBottomMargin = 7.0; -const CGFloat ButtonSideMargin = 9.0; - -// looks better with some margins -const CGFloat DialogTopMargin = 7.0; -const CGFloat DialogSideMargin = 9.0; - -static NSButton *macCreateButton(const char *text, NSView *superview) -{ - static const NSRect buttonFrameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } }; - - NSButton *button = [[NSButton alloc] initWithFrame:buttonFrameRect]; - [button setButtonType:NSMomentaryLightButton]; - [button setBezelStyle:NSRoundedBezelStyle]; - [button setTitle:(NSString*)(CFStringRef)QCFString( - QPlatformTheme::removeMnemonics(QCoreApplication::translate("QDialogButtonBox", text)))]; - [[button cell] setFont:[NSFont systemFontOfSize: - [NSFont systemFontSizeForControlSize:NSRegularControlSize]]]; - [superview addSubview:button]; - return button; -} - static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) { QFont newFont; @@ -103,22 +76,19 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) @class QT_MANGLE_NAMESPACE(QNSFontPanelDelegate); -@interface QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) : NSObject +@interface QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) : NSObject { @public NSFontPanel *mFontPanel; QCocoaFontDialogHelper *mHelper; NSView *mStolenContentView; - NSButton *mOkButton; - NSButton *mCancelButton; + QNSPanelContentsWrapper *mPanelButtons; QFont mQtFont; NSInteger mResultCode; BOOL mDialogIsExecuting; BOOL mResultSet; }; - (void)restoreOriginalContentView; -- (void)relayout; -- (void)relayoutToContentSize:(NSSize)frameSize; - (void)updateQtFont; - (void)changeFont:(id)sender; - (void)finishOffWithCode:(NSInteger)code; @@ -134,8 +104,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); mFontPanel = [NSFontPanel sharedFontPanel]; mHelper = 0; mStolenContentView = 0; - mOkButton = 0; - mCancelButton = 0; + mPanelButtons = 0; mResultCode = NSCancelButton; mDialogIsExecuting = false; mResultSet = false; @@ -173,23 +142,11 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); [mFontPanel setContentView:0]; // create a new content view and add the stolen one as a subview - NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } }; - NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect]; - [ourContentView addSubview:mStolenContentView]; - - // create OK and Cancel buttons and add these as subviews - mOkButton = macCreateButton("&OK", ourContentView); - mCancelButton = macCreateButton("Cancel", ourContentView); - - [mFontPanel setContentView:ourContentView]; - [mFontPanel setDefaultButtonCell:[mOkButton cell]]; - [self relayoutToContentSize:[[mStolenContentView superview] frame].size]; - - [mOkButton setAction:@selector(onOkClicked)]; - [mOkButton setTarget:self]; - - [mCancelButton setAction:@selector(onCancelClicked)]; - [mCancelButton setTarget:self]; + mPanelButtons = [[QNSPanelContentsWrapper alloc] initWithPanelDelegate:self]; + [mPanelButtons addSubview:mStolenContentView]; + mPanelButtons.panelContentsMargins = NSEdgeInsetsMake(0, 0, 7, 0); + mFontPanel.contentView = mPanelButtons; + mFontPanel.defaultButtonCell = mPanelButtons.okButton.cell; } } @@ -198,77 +155,18 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); [mFontPanel close]; } -- (void)windowDidResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - [self relayout]; -} - - (void)restoreOriginalContentView { if (mStolenContentView) { - NSView *ourContentView = [mFontPanel contentView]; - // return stolen stuff to its rightful owner [mStolenContentView removeFromSuperview]; [mFontPanel setContentView:mStolenContentView]; - [mOkButton release]; - [mCancelButton release]; - [ourContentView release]; - mOkButton = 0; - mCancelButton = 0; mStolenContentView = 0; + [mPanelButtons release]; + mPanelButtons = nil; } } -- (void)relayout -{ - if (!mOkButton) - return; - - [self relayoutToContentSize:[[mStolenContentView superview] frame].size]; -} - -- (void)relayoutToContentSize:(NSSize)frameSize -{ - Q_ASSERT(mOkButton); - - [mOkButton sizeToFit]; - NSSize okSizeHint = [mOkButton frame].size; - - [mCancelButton sizeToFit]; - NSSize cancelSizeHint = [mCancelButton frame].size; - - const CGFloat ButtonWidth = qMin(qMax(ButtonMinWidth, - qMax(okSizeHint.width, cancelSizeHint.width)), - CGFloat((frameSize.width - 2.0 * ButtonSideMargin - ButtonSpacing) * 0.5)); - const CGFloat ButtonHeight = qMax(ButtonMinHeight, - qMax(okSizeHint.height, cancelSizeHint.height)); - - const CGFloat X = DialogSideMargin; - const CGFloat Y = ButtonBottomMargin + ButtonHeight + ButtonTopMargin; - - NSRect okRect = { { frameSize.width - ButtonSideMargin - ButtonWidth, - ButtonBottomMargin }, - { ButtonWidth, ButtonHeight } }; - [mOkButton setFrame:okRect]; - [mOkButton setNeedsDisplay:YES]; - - NSRect cancelRect = { { okRect.origin.x - ButtonSpacing - ButtonWidth, - ButtonBottomMargin }, - { ButtonWidth, ButtonHeight } }; - [mCancelButton setFrame:cancelRect]; - [mCancelButton setNeedsDisplay:YES]; - - NSRect stolenCVRect = { { X, Y }, - { frameSize.width - X - X, frameSize.height - Y - DialogTopMargin } }; - [mStolenContentView setFrame:stolenCVRect]; - [mStolenContentView setNeedsDisplay:YES]; - - [[mStolenContentView superview] setNeedsDisplay:YES]; -} - - - (void)onOkClicked { [mFontPanel close]; @@ -277,7 +175,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); - (void)onCancelClicked { - if (mOkButton) { + if (mPanelButtons) { [mFontPanel close]; mQtFont = QFont(); [self finishOffWithCode:NSCancelButton]; @@ -332,7 +230,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); - (BOOL)windowShouldClose:(id)window { Q_UNUSED(window); - if (!mOkButton) + if (!mPanelButtons) [self updateQtFont]; if (mDialogIsExecuting) { [self finishOffWithCode:NSCancelButton]; diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 1b038a6b5e..a2e0876073 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -158,7 +158,30 @@ T qt_mac_resolveOption(const T &fallback, QWindow *window, const QByteArray &pro // return default value. return fallback; } + QT_END_NAMESPACE +@protocol QT_MANGLE_NAMESPACE(QNSPanelDelegate) +@required +- (void)onOkClicked; +- (void)onCancelClicked; +@end + +@interface QT_MANGLE_NAMESPACE(QNSPanelContentsWrapper) : NSView + +@property (nonatomic, readonly) NSButton *okButton; +@property (nonatomic, readonly) NSButton *cancelButton; +@property (nonatomic, readonly) NSView *panelContents; // ARC: unretained, make it weak +@property (nonatomic, assign) NSEdgeInsets panelContentsMargins; + +- (instancetype)initWithPanelDelegate:(id)panelDelegate; +- (void)dealloc; + +- (NSButton *)createButtonWithTitle:(const char *)title; +- (void)layout; +@end + +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanelContentsWrapper); + #endif //QCOCOAHELPERS_H diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index c57567bdd6..01fbb7bad2 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -300,3 +300,117 @@ QString qt_mac_removeAmpersandEscapes(QString s) } QT_END_NAMESPACE + +/*! \internal + + This NSView derived class is used to add OK/Cancel + buttons to NSColorPanel and NSFontPanel. It replaces + the panel's content view, while reparenting the former + content view into itself. It also takes care of setting + the target-action for the OK/Cancel buttons and making + sure the layout is consistent. + */ +@implementation QNSPanelContentsWrapper + +- (instancetype)initWithPanelDelegate:(id)panelDelegate +{ + if ((self = [super initWithFrame:NSZeroRect])) { + // create OK and Cancel buttons and add these as subviews + _okButton = [self createButtonWithTitle:"&OK"]; + _okButton.action = @selector(onOkClicked); + _okButton.target = panelDelegate; + + _cancelButton = [self createButtonWithTitle:"Cancel"]; + _cancelButton.action = @selector(onCancelClicked); + _cancelButton.target = panelDelegate; + + _panelContents = nil; + + _panelContentsMargins = NSEdgeInsetsMake(0, 0, 0, 0); + } + + return self; +} + +- (void)dealloc +{ + [_okButton release]; + _okButton = nil; + [_cancelButton release]; + _cancelButton = nil; + + _panelContents = nil; + + [super dealloc]; +} + +- (NSButton *)createButtonWithTitle:(const char *)title +{ + NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect]; + button.buttonType = NSMomentaryLightButton; + button.bezelStyle = NSRoundedBezelStyle; + const QString &cleanTitle = QPlatformTheme::removeMnemonics(QCoreApplication::translate("QDialogButtonBox", title)); + // FIXME: Not obvious, from Cocoa's documentation, that QString::toNSString() makes a deep copy + button.title = (NSString *)cleanTitle.toCFString(); + ((NSButtonCell *)button.cell).font = + [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; + [self addSubview:button]; + return button; +} + +- (void)layout +{ + static const CGFloat ButtonMinWidth = 78.0; // 84.0 for Carbon + static const CGFloat ButtonMinHeight = 32.0; + static const CGFloat ButtonSpacing = 0.0; + static const CGFloat ButtonTopMargin = 0.0; + static const CGFloat ButtonBottomMargin = 7.0; + static const CGFloat ButtonSideMargin = 9.0; + + NSSize frameSize = self.frame.size; + + [self.okButton sizeToFit]; + NSSize okSizeHint = self.okButton.frame.size; + + [self.cancelButton sizeToFit]; + NSSize cancelSizeHint = self.cancelButton.frame.size; + + const CGFloat buttonWidth = qMin(qMax(ButtonMinWidth, + qMax(okSizeHint.width, cancelSizeHint.width)), + CGFloat((frameSize.width - 2.0 * ButtonSideMargin - ButtonSpacing) * 0.5)); + const CGFloat buttonHeight = qMax(ButtonMinHeight, + qMax(okSizeHint.height, cancelSizeHint.height)); + + NSRect okRect = { { frameSize.width - ButtonSideMargin - buttonWidth, + ButtonBottomMargin }, + { buttonWidth, buttonHeight } }; + self.okButton.frame = okRect; + self.okButton.needsDisplay = YES; + + NSRect cancelRect = { { okRect.origin.x - ButtonSpacing - buttonWidth, + ButtonBottomMargin }, + { buttonWidth, buttonHeight } }; + self.cancelButton.frame = cancelRect; + self.cancelButton.needsDisplay = YES; + + // The third view should be the original panel contents. Cache it. + if (!self.panelContents) + for (NSView *view in self.subviews) + if (view != self.okButton && view != self.cancelButton) { + _panelContents = view; + break; + } + + const CGFloat buttonBoxHeight = ButtonBottomMargin + buttonHeight + ButtonTopMargin; + const NSRect panelContentsFrame = NSMakeRect( + self.panelContentsMargins.left, + buttonBoxHeight + self.panelContentsMargins.bottom, + frameSize.width - (self.panelContentsMargins.left + self.panelContentsMargins.right), + frameSize.height - buttonBoxHeight - (self.panelContentsMargins.top + self.panelContentsMargins.bottom)); + self.panelContents.frame = panelContentsFrame; + self.panelContents.needsDisplay = YES; + + self.needsDisplay = YES; +} + +@end