Add QCocoaColor- and FontDialogHelper

Change-Id: Ie6e648e9e1f4ffbb34d73f9afdd6cc77e86bc3d1
Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
This commit is contained in:
Christoph Schleifenbaum 2012-01-31 16:15:51 +01:00 committed by Qt by Nokia
parent 647aa53d72
commit 2907fbd898
7 changed files with 1140 additions and 8 deletions

View File

@ -23,7 +23,9 @@ OBJECTIVE_SOURCES += main.mm \
qmultitouch_mac.mm \
qcocoaaccessibilityelement.mm \
qcocoaaccessibility.mm \
qcocoacolordialoghelper.mm \
qcocoafiledialoghelper.mm \
qcocoafontdialoghelper.mm \
qcocoacursor.mm \
HEADERS += qcocoaintegration.h \
@ -45,7 +47,9 @@ HEADERS += qcocoaintegration.h \
qmultitouch_mac_p.h \
qcocoaaccessibilityelement.h \
qcocoaaccessibility.h \
qcocoacolordialoghelper.h \
qcocoafiledialoghelper.h \
qcocoafontdialoghelper.h \
qcocoacursor.h \
FORMS += $$PWD/../../../widgets/dialogs/qfiledialog.ui

View File

@ -0,0 +1,78 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCOCOACOLORDIALOGHELPER_H
#define QCOCOACOLORDIALOGHELPER_H
#include <QObject>
#include <qplatformdialoghelper_qpa.h>
QT_BEGIN_NAMESPACE
class QCocoaColorDialogHelper : public QPlatformColorDialogHelper
{
public:
QCocoaColorDialogHelper();
virtual ~QCocoaColorDialogHelper();
void platformNativeDialogModalHelp();
void _q_platformRunNativeAppModalPanel();
void deleteNativeDialog_sys();
bool show_sys(QFlags<QPlatformDialogHelper::ShowFlag>, Qt::WindowFlags, QWindow*);
void hide_sys();
DialogCode dialogResultCode_sys();
void setCurrentColor_sys(const QColor&);
QColor currentColor_sys() const;
public:
bool showCocoaColorPanel(QWindow *parent);
bool hideCocoaColorPanel();
void createNSColorPanelDelegate();
private:
void *mDelegate;
};
QT_END_NAMESPACE
#endif // QCOCOACOLORDIALOGHELPER_H

View File

@ -0,0 +1,465 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcocoacolordialoghelper.h"
#ifndef QT_NO_COLORDIALOG
#include <QtCore/qdebug.h>
#include <QtCore/qtimer.h>
#include <QtWidgets/qdialogbuttonbox.h>
#include <QtWidgets/qcolordialog.h>
#include "qcocoahelpers.h"
#import <AppKit/AppKit.h>
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(QDialogButtonBox::tr(text)
.remove(QLatin1Char('&')))];
[[button cell] setFont:[NSFont systemFontOfSize:
[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
[superview addSubview:button];
return button;
}
@class QT_MANGLE_NAMESPACE(QNSColorPanelDelegate);
@interface QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) : NSObject<NSWindowDelegate>
{
@public
NSColorPanel *mColorPanel;
QCocoaColorDialogHelper *mHelper;
NSView *mStolenContentView;
NSButton *mOkButton;
NSButton *mCancelButton;
QColor mQtColor;
NSInteger mResultCode;
BOOL mDialogIsExecuting;
BOOL mResultSet;
};
- (void)relayout;
- (void)updateQtColor;
- (void)finishOffWithCode:(NSInteger)code;
@end
@implementation QT_MANGLE_NAMESPACE(QNSColorPanelDelegate)
- (id)initWithDialogHelper:(QCocoaColorDialogHelper *)helper
{
self = [super init];
mColorPanel = [NSColorPanel sharedColorPanel];
mHelper = helper;
mResultCode = NSCancelButton;
mDialogIsExecuting = false;
mResultSet = false;
if (mHelper->options()->testOption(QColorDialogOptions::NoButtons)) {
mStolenContentView = 0;
mOkButton = 0;
mCancelButton = 0;
} else {
// steal the color panel's contents view
mStolenContentView = [mColorPanel contentView];
[mStolenContentView retain];
[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];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(colorChanged:)
name:NSColorPanelColorDidChangeNotification
object:mColorPanel];
[mColorPanel retain];
return self;
}
- (void)dealloc
{
if (mOkButton) {
NSView *ourContentView = [mColorPanel contentView];
// return stolen stuff to its rightful owner
[mStolenContentView removeFromSuperview];
[mColorPanel setContentView:mStolenContentView];
[mOkButton release];
[mCancelButton release];
[ourContentView release];
}
[mColorPanel setDelegate:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)closePanel
{
[mColorPanel close];
}
- (void)windowDidResize:(NSNotification *)notification
{
Q_UNUSED(notification);
[self relayout];
}
- (void)colorChanged:(NSNotification *)notification
{
Q_UNUSED(notification);
[self updateQtColor];
emit mHelper->colorSelected(mQtColor);
}
- (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
{
Q_ASSERT(mHackedPanel);
[mColorPanel close];
[self updateQtColor];
[self finishOffWithCode:NSOKButton];
}
- (void)onCancelClicked
{
if (mOkButton) {
[mColorPanel close];
mQtColor = QColor();
[self finishOffWithCode:NSCancelButton];
}
}
- (void)updateQtColor
{
NSColor *color = [mColorPanel color];
NSString *colorSpaceName = [color colorSpaceName];
if (colorSpaceName == NSDeviceCMYKColorSpace) {
CGFloat cyan = 0, magenta = 0, yellow = 0, black = 0, alpha = 0;
[color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
mQtColor.setCmykF(cyan, magenta, yellow, black, alpha);
} else if (colorSpaceName == NSCalibratedRGBColorSpace || colorSpaceName == NSDeviceRGBColorSpace) {
CGFloat red = 0, green = 0, blue = 0, alpha = 0;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
mQtColor.setRgbF(red, green, blue, alpha);
} else if (colorSpaceName == NSNamedColorSpace) {
NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
CGFloat red = 0, green = 0, blue = 0, alpha = 0;
[tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
mQtColor.setRgbF(red, green, blue, alpha);
} else {
NSColorSpace *colorSpace = [color colorSpace];
if ([colorSpace colorSpaceModel] == NSCMYKColorSpaceModel && [color numberOfComponents] == 5){
CGFloat components[5];
[color getComponents:components];
mQtColor.setCmykF(components[0], components[1], components[2], components[3], components[4]);
} else {
NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
CGFloat red = 0, green = 0, blue = 0, alpha = 0;
[tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
mQtColor.setRgbF(red, green, blue, alpha);
}
}
emit mHelper->currentColorChanged(mQtColor);
}
- (void)showModelessPanel
{
mDialogIsExecuting = false;
[mColorPanel makeKeyAndOrderFront:mColorPanel];
}
- (BOOL)runApplicationModalPanel
{
mDialogIsExecuting = true;
[mColorPanel setDelegate:self];
[mColorPanel setContinuous:YES];
[NSApp runModalForWindow:mColorPanel];
return (mResultCode == NSOKButton);
}
- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode
{
return (mResultCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected);
}
- (BOOL)windowShouldClose:(id)window
{
Q_UNUSED(window);
if (!mOkButton)
[self updateQtColor];
if (mDialogIsExecuting) {
[self finishOffWithCode:NSCancelButton];
} else {
mResultSet = true;
emit mHelper->reject();
}
return true;
}
- (void)finishOffWithCode:(NSInteger)code
{
mResultCode = code;
if (mDialogIsExecuting) {
// We stop the current modal event loop. The control
// will then return inside -(void)exec below.
// It's important that the modal event loop is stopped before
// we accept/reject QColorDialog, since QColorDialog has its
// own event loop that needs to be stopped last.
[NSApp stopModalWithCode:code];
} else {
// Since we are not in a modal event loop, we can safely close
// down QColorDialog
// Calling accept() or reject() can in turn call closeCocoaColorPanel.
// This check will prevent any such recursion.
if (!mResultSet) {
mResultSet = true;
if (mResultCode == NSCancelButton) {
emit mHelper->reject();
} else {
emit mHelper->accept();
}
}
}
}
@end
QT_BEGIN_NAMESPACE
QCocoaColorDialogHelper::QCocoaColorDialogHelper() :
mDelegate(0)
{
}
QCocoaColorDialogHelper::~QCocoaColorDialogHelper()
{
deleteNativeDialog_sys();
}
void QCocoaColorDialogHelper::platformNativeDialogModalHelp()
{
// Do a queued meta-call to open the native modal dialog so it opens after the new
// event loop has started to execute (in QDialog::exec). Using a timer rather than
// a queued meta call is intentional to ensure that the call is only delivered when
// [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
// running (which is the case if e.g a top-most QEventLoop has been
// interrupted, and the second-most event loop has not yet been reactivated (regardless
// if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
QTimer::singleShot(1, this, SIGNAL(launchNativeAppModalPanel()));
}
void QCocoaColorDialogHelper::_q_platformRunNativeAppModalPanel()
{
// TODO:
#if 0
QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
#endif
QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate);
[delegate runApplicationModalPanel];
if (dialogResultCode_sys() == QPlatformDialogHelper::Accepted)
emit accept();
else
emit reject();
}
void QCocoaColorDialogHelper::deleteNativeDialog_sys()
{
if (!mDelegate)
return;
[reinterpret_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate) release];
mDelegate = 0;
}
bool QCocoaColorDialogHelper::show_sys(QFlags<QPlatformDialogHelper::ShowFlag>, Qt::WindowFlags, QWindow *parent)
{
return showCocoaColorPanel(parent);
}
void QCocoaColorDialogHelper::hide_sys()
{
if (!mDelegate)
return;
[reinterpret_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate)->mColorPanel close];
}
QCocoaColorDialogHelper::DialogCode QCocoaColorDialogHelper::dialogResultCode_sys()
{
QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate);
return [delegate dialogResultCode];
}
void QCocoaColorDialogHelper::setCurrentColor_sys(const QColor &color)
{
if (!mDelegate)
createNSColorPanelDelegate();
QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate);
NSColor *nsColor;
const QColor::Spec spec = color.spec();
if (spec == QColor::Cmyk) {
nsColor = [NSColor colorWithDeviceCyan:color.cyanF()
magenta:color.magentaF()
yellow:color.yellowF()
black:color.blackF()
alpha:color.alphaF()];
} else {
nsColor = [NSColor colorWithCalibratedRed:color.redF()
green:color.greenF()
blue:color.blueF()
alpha:color.alphaF()];
}
delegate->mQtColor = color;
[delegate->mColorPanel setColor:nsColor];
}
QColor QCocoaColorDialogHelper::currentColor_sys() const
{
return reinterpret_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate)->mQtColor;
}
void QCocoaColorDialogHelper::createNSColorPanelDelegate()
{
if (mDelegate)
return;
QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) alloc]
initWithDialogHelper:this];
mDelegate = delegate;
}
bool QCocoaColorDialogHelper::showCocoaColorPanel(QWindow *parent)
{
Q_UNUSED(parent);
createNSColorPanelDelegate();
QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate);
[delegate->mColorPanel setShowsAlpha:options()->testOption(QColorDialogOptions::ShowAlphaChannel)];
[delegate showModelessPanel];
return true;
}
bool QCocoaColorDialogHelper::hideCocoaColorPanel()
{
if (!mDelegate){
return false;
} else {
QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *>(mDelegate);
[delegate closePanel];
return true;
}
}
QT_END_NAMESPACE
#endif // QT_NO_COLORDIALOG

View File

@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCOCOAFONTDIALOGHELPER_H
#define QCOCOAFONTDIALOGHELPER_H
#include <QObject>
#include <qplatformdialoghelper_qpa.h>
QT_BEGIN_NAMESPACE
class QFontDialog;
class QFontDialogPrivate;
class QCocoaFontDialogHelper : public QPlatformFontDialogHelper
{
public:
QCocoaFontDialogHelper();
virtual ~QCocoaFontDialogHelper();
void platformNativeDialogModalHelp();
void _q_platformRunNativeAppModalPanel();
void deleteNativeDialog_sys();
bool show_sys(ShowFlags showFlags, Qt::WindowFlags windowFlags, QWindow *parent);
void hide_sys();
QPlatformDialogHelper::DialogCode dialogResultCode_sys();
void setCurrentFont_sys(const QFont &);
QFont currentFont_sys() const;
protected:
void createNSFontPanelDelegate();
bool showCocoaFontPanel(QWindow *parent);
bool hideCocoaFontPanel();
private:
void *mDelegate;
};
QT_END_NAMESPACE
#endif // QCOCOAFONTDIALOGHELPER_H

View File

@ -0,0 +1,488 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcocoafontdialoghelper.h"
#ifndef QT_NO_FONTDIALOG
#include <QtCore/qtimer.h>
#include <QtGui/qfontdatabase.h>
#include <QtWidgets/qdialogbuttonbox.h>
#include <QtWidgets/qfontdialog.h>
#include <private/qfont_p.h>
#include <private/qfontengine_p.h>
#include <private/qfontengine_coretext_p.h>
#include "qcocoahelpers.h"
#import <AppKit/AppKit.h>
#if !CGFLOAT_DEFINED
typedef float CGFloat; // Should only not be defined on 32-bit platforms
#endif
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(QDialogButtonBox::tr(text)
.remove(QLatin1Char('&')))];
[[button cell] setFont:[NSFont systemFontOfSize:
[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
[superview addSubview:button];
return button;
}
static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
{
QFont newFont;
if (cocoaFont) {
int pSize = qRound([cocoaFont pointSize]);
QString family(QCFString::toQString([cocoaFont familyName]));
QString typeface(QCFString::toQString([cocoaFont fontName]));
int hyphenPos = typeface.indexOf(QLatin1Char('-'));
if (hyphenPos != -1) {
typeface.remove(0, hyphenPos + 1);
} else {
typeface = QLatin1String("Normal");
}
newFont = QFontDatabase().font(family, typeface, pSize);
newFont.setUnderline(resolveFont.underline());
newFont.setStrikeOut(resolveFont.strikeOut());
}
return newFont;
}
@class QT_MANGLE_NAMESPACE(QNSFontPanelDelegate);
@interface QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) : NSObject<NSWindowDelegate>
{
@public
NSFontPanel *mFontPanel;
QCocoaFontDialogHelper *mHelper;
NSView *mStolenContentView;
NSButton *mOkButton;
NSButton *mCancelButton;
QFont mQtFont;
NSInteger mResultCode;
BOOL mDialogIsExecuting;
BOOL mResultSet;
};
- (void)relayout;
- (void)relayoutToContentSize:(NSSize)frameSize;
- (void)updateQtFont;
- (void)changeFont:(id)sender;
- (void)finishOffWithCode:(NSInteger)code;
@end
@implementation QT_MANGLE_NAMESPACE(QNSFontPanelDelegate)
- (id)initWithDialogHelper:
(QCocoaFontDialogHelper *)helper
{
self = [super init];
mFontPanel = [NSFontPanel sharedFontPanel];
mHelper = helper;
mResultCode = NSCancelButton;
mDialogIsExecuting = false;
mResultSet = false;
[mFontPanel setTitle:QCFString::toNSString(helper->options()->windowTitle())];
if (mHelper->options()->testOption(QFontDialogOptions::NoButtons)) {
mStolenContentView = 0;
mOkButton = 0;
mCancelButton = 0;
} else {
// steal the font panel's contents view
mStolenContentView = [mFontPanel contentView];
[mStolenContentView retain];
[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];
}
[mFontPanel retain];
return self;
}
- (void)dealloc
{
if (mOkButton) {
NSView *ourContentView = [mFontPanel contentView];
// return stolen stuff to its rightful owner
[mStolenContentView removeFromSuperview];
[mFontPanel setContentView:mStolenContentView];
[mOkButton release];
[mCancelButton release];
[ourContentView release];
}
[mFontPanel setDelegate:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)closePanel
{
[mFontPanel close];
}
- (void)windowDidResize:(NSNotification *)notification
{
Q_UNUSED(notification);
if (mOkButton)
[self relayout];
}
- (void)relayout
{
[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
{
Q_ASSERT(mHackedPanel);
[mFontPanel close];
[self finishOffWithCode:NSOKButton];
}
- (void)onCancelClicked
{
if (mOkButton) {
[mFontPanel close];
mQtFont = QFont();
[self finishOffWithCode:NSCancelButton];
}
}
- (void)changeFont:(id)sender
{
Q_UNUSED(sender);
[self updateQtFont];
}
- (void)updateQtFont
{
// Get selected font
NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSFont *selectedFont = [fontManager selectedFont];
if (selectedFont == nil) {
selectedFont = [NSFont systemFontOfSize:[NSFont systemFontSize]];
}
NSFont *panelFont = [fontManager convertFont:selectedFont];
mQtFont = qfontForCocoaFont(panelFont, mQtFont);
emit mHelper->currentFontChanged(mQtFont);
}
- (void)showModelessPanel
{
mDialogIsExecuting = false;
[mFontPanel makeKeyAndOrderFront:mFontPanel];
}
- (BOOL)runApplicationModalPanel
{
mDialogIsExecuting = true;
[mFontPanel setDelegate:self];
[NSApp runModalForWindow:mFontPanel];
return (mResultCode == NSOKButton);
}
- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode
{
return (mResultCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected);
}
- (BOOL)windowShouldClose:(id)window
{
Q_UNUSED(window);
if (!mOkButton)
[self updateQtFont];
if (mDialogIsExecuting) {
[self finishOffWithCode:NSCancelButton];
} else {
mResultSet = true;
emit mHelper->reject();
}
return true;
}
- (void)finishOffWithCode:(NSInteger)code
{
mResultCode = code;
if (mDialogIsExecuting) {
// We stop the current modal event loop. The control
// will then return inside -(void)exec below.
// It's important that the modal event loop is stopped before
// we accept/reject QFontDialog, since QFontDialog has its
// own event loop that needs to be stopped last.
[NSApp stopModalWithCode:code];
} else {
// Since we are not in a modal event loop, we can safely close
// down QFontDialog
// Calling accept() or reject() can in turn call closeCocoaFontPanel.
// This check will prevent any such recursion.
if (!mResultSet) {
mResultSet = true;
if (mResultCode == NSCancelButton) {
emit mHelper->reject();
} else {
emit mHelper->accept();
}
}
}
}
@end
QT_BEGIN_NAMESPACE
QCocoaFontDialogHelper::QCocoaFontDialogHelper() :
mDelegate(0)
{
}
QCocoaFontDialogHelper::~QCocoaFontDialogHelper()
{
deleteNativeDialog_sys();
}
void QCocoaFontDialogHelper::platformNativeDialogModalHelp()
{
// Do a queued meta-call to open the native modal dialog so it opens after the new
// event loop has started to execute (in QDialog::exec). Using a timer rather than
// a queued meta call is intentional to ensure that the call is only delivered when
// [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
// running (which is the case if e.g a top-most QEventLoop has been
// interrupted, and the second-most event loop has not yet been reactivated (regardless
// if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
QTimer::singleShot(1, this, SIGNAL(launchNativeAppModalPanel()));
}
void QCocoaFontDialogHelper::_q_platformRunNativeAppModalPanel()
{
// TODO:
#if 0
QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
#endif
QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate);
[delegate runApplicationModalPanel];
if (dialogResultCode_sys() == QPlatformDialogHelper::Accepted)
emit accept();
else
emit reject();
}
void QCocoaFontDialogHelper::deleteNativeDialog_sys()
{
if (!mDelegate)
return;
[reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate) release];
mDelegate = 0;
}
bool QCocoaFontDialogHelper::show_sys(QFlags<QPlatformDialogHelper::ShowFlag>, Qt::WindowFlags, QWindow *parent)
{
return showCocoaFontPanel(parent);
}
void QCocoaFontDialogHelper::hide_sys()
{
if (!mDelegate)
return;
[reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mFontPanel close];
}
QCocoaFontDialogHelper::DialogCode QCocoaFontDialogHelper::dialogResultCode_sys()
{
QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate);
return [delegate dialogResultCode];
}
void QCocoaFontDialogHelper::setCurrentFont_sys(const QFont &font)
{
NSFontManager *mgr = [NSFontManager sharedFontManager];
const NSFont *nsFont = 0;
int weight = 5;
NSFontTraitMask mask = 0;
if (font.style() == QFont::StyleItalic) {
mask |= NSItalicFontMask;
}
if (font.weight() == QFont::Bold) {
weight = 9;
mask |= NSBoldFontMask;
}
QFontInfo fontInfo(font);
nsFont = [mgr fontWithFamily:QCFString::toNSString(fontInfo.family())
traits:mask
weight:weight
size:fontInfo.pointSize()];
if (!mDelegate)
createNSFontPanelDelegate();
[mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO];
static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mQtFont = font;
}
QFont QCocoaFontDialogHelper::currentFont_sys() const
{
return reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mQtFont;
}
void QCocoaFontDialogHelper::createNSFontPanelDelegate()
{
if (mDelegate)
return;
QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) alloc]
initWithDialogHelper:this];
mDelegate = delegate;
}
bool QCocoaFontDialogHelper::showCocoaFontPanel(QWindow *parent)
{
Q_UNUSED(parent);
createNSFontPanelDelegate();
QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate);
[delegate showModelessPanel];
return true;
}
bool QCocoaFontDialogHelper::hideCocoaFontPanel()
{
if (!mDelegate){
return false;
} else {
QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate);
[delegate closePanel];
return true;
}
}
QT_END_NAMESPACE
#endif // QT_NO_FONTDIALOG

View File

@ -42,8 +42,9 @@
#include "qcocoatheme.h"
#include "qmenu_mac.h"
#include "qcocoacolordialoghelper.h"
#include "qcocoafiledialoghelper.h"
#include <QtWidgets/QFileDialog>
#include "qcocoafontdialoghelper.h"
QT_BEGIN_NAMESPACE
@ -72,15 +73,33 @@ bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const
{
if (dialogType == QPlatformTheme::FileDialog)
return true;
#ifndef QT_NO_COLORDIALOG
if (dialogType == QPlatformTheme::ColorDialog)
return true;
#endif
#ifndef QT_NO_FONTDIALOG
if (dialogType == QPlatformTheme::FontDialog)
return true;
#endif
return false;
}
QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const
{
if (dialogType == QPlatformTheme::FileDialog) {
switch (dialogType) {
case QPlatformTheme::FileDialog:
return new QCocoaFileDialogHelper();
#ifndef QT_NO_COLORDIALOG
case QPlatformTheme::ColorDialog:
return new QCocoaColorDialogHelper();
#endif
#ifndef QT_NO_FONTDIALOG
case QPlatformTheme::FontDialog:
return new QCocoaFontDialogHelper();
#endif
default:
return 0;
}
return 0;
}
QT_END_NAMESPACE

View File

@ -1440,7 +1440,7 @@ void QColorDialogPrivate::init(const QColor &initial)
q->setSizeGripEnabled(false);
q->setWindowTitle(QColorDialog::tr("Select Color"));
nativeDialogInUse = false;
nativeDialogInUse = (platformColorDialogHelper() != 0);
nextCust = 0;
QVBoxLayout *mainLay = new QVBoxLayout(q);
@ -1697,10 +1697,6 @@ void QColorDialog::setCurrentColor(const QColor &color)
d->selectColor(color);
d->setCurrentAlpha(color.alpha());
#ifdef Q_WS_MAC
d->setCurrentQColor(color);
d->setCocoaPanelColor(color);
#endif
// ### fixme: Call helper
if (d->nativeDialogInUse)
d->platformColorDialogHelper()->setCurrentColor_sys(color);