From f52f6e2d44bc3a08a5b2fa281459af8baac68f0d Mon Sep 17 00:00:00 2001 From: Keith Bennett Date: Sat, 22 Mar 2014 17:02:43 +0000 Subject: [PATCH] Squashed 'src/gui/qocoa/' content from commit ffe23cb git-subtree-dir: src/gui/qocoa git-subtree-split: ffe23cbb2f221bc9eacd1de2134c2947fed71c12 --- .gitignore | 2 + CMakeLists.txt | 48 +++++ LICENSE.txt | 19 ++ Qocoa.pro | 17 ++ README.md | 36 ++++ TODO.md | 13 ++ gallery.cpp | 75 +++++++ gallery.h | 14 ++ gallery.png | Bin 0 -> 42195 bytes main.cpp | 13 ++ qbutton.h | 49 +++++ qbutton_mac.mm | 229 +++++++++++++++++++++ qbutton_nonmac.cpp | 89 +++++++++ qocoa_mac.h | 63 ++++++ qprogressindicatorspinning.h | 29 +++ qprogressindicatorspinning_mac.mm | 70 +++++++ qprogressindicatorspinning_nonmac.cpp | 72 +++++++ qprogressindicatorspinning_nonmac.gif | Bin 0 -> 3208 bytes qprogressindicatorspinning_nonmac.qrc | 5 + qsearchfield.h | 48 +++++ qsearchfield_mac.mm | 262 +++++++++++++++++++++++++ qsearchfield_nonmac.cpp | 256 ++++++++++++++++++++++++ qsearchfield_nonmac.qrc | 7 + qsearchfield_nonmac_clear.png | Bin 0 -> 736 bytes qsearchfield_nonmac_magnifier.png | Bin 0 -> 300 bytes qsearchfield_nonmac_magnifier_menu.png | Bin 0 -> 439 bytes 26 files changed, 1416 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE.txt create mode 100644 Qocoa.pro create mode 100644 README.md create mode 100644 TODO.md create mode 100644 gallery.cpp create mode 100644 gallery.h create mode 100644 gallery.png create mode 100644 main.cpp create mode 100644 qbutton.h create mode 100644 qbutton_mac.mm create mode 100644 qbutton_nonmac.cpp create mode 100644 qocoa_mac.h create mode 100644 qprogressindicatorspinning.h create mode 100644 qprogressindicatorspinning_mac.mm create mode 100644 qprogressindicatorspinning_nonmac.cpp create mode 100644 qprogressindicatorspinning_nonmac.gif create mode 100644 qprogressindicatorspinning_nonmac.qrc create mode 100644 qsearchfield.h create mode 100644 qsearchfield_mac.mm create mode 100644 qsearchfield_nonmac.cpp create mode 100644 qsearchfield_nonmac.qrc create mode 100644 qsearchfield_nonmac_clear.png create mode 100644 qsearchfield_nonmac_magnifier.png create mode 100644 qsearchfield_nonmac_magnifier_menu.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..4963d2730 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cmake/ +qmake/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..513f81f7d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,48 @@ +project(Qocoa) +cmake_minimum_required(VERSION 2.8) + +find_package(Qt4 COMPONENTS QtMain QtCore QtGui REQUIRED) +include(UseQt4) + +set(SOURCES + main.cpp + gallery.cpp +) + +set(HEADERS + gallery.h + qsearchfield.h + qbutton.h + qprogressindicatorspinning.h +) + +qt4_wrap_cpp(MOC_SOURCES ${HEADERS}) + +if(APPLE) + list(APPEND SOURCES + qsearchfield_mac.mm + qbutton_mac.mm + qprogressindicatorspinning_mac.mm + ) +else() + list(APPEND SOURCES + qsearchfield_nonmac.cpp + qbutton_nonmac.cpp + qprogressindicatorspinning_nonmac.cpp + ) + set(RESOURCES + qsearchfield_nonmac.qrc + qprogressindicatorspinning_nonmac.qrc + ) + qt4_add_resources(RESOURCES_SOURCES ${RESOURCES}) +endif() + +add_executable(Qocoa + WIN32 MACOSX_BUNDLE + ${SOURCES} ${MOC_SOURCES} ${RESOURCES_SOURCES} +) +target_link_libraries(Qocoa ${QT_LIBRARIES}) + +if(APPLE) + set_target_properties(Qocoa PROPERTIES LINK_FLAGS "-framework Foundation -framework AppKit") +endif() diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..910eb6d20 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Qocoa.pro b/Qocoa.pro new file mode 100644 index 000000000..8b325d192 --- /dev/null +++ b/Qocoa.pro @@ -0,0 +1,17 @@ +SOURCES += main.cpp\ + gallery.cpp \ + +HEADERS += gallery.h \ + qocoa_mac.h \ + qsearchfield.h \ + qbutton.h \ + qprogressindicatorspinning.h \ + +mac { + OBJECTIVE_SOURCES += qsearchfield_mac.mm qbutton_mac.mm qprogressindicatorspinning_mac.mm + LIBS += -framework Foundation -framework Appkit + QMAKE_CFLAGS += -mmacosx-version-min=10.6 +} else { + SOURCES += qsearchfield_nonmac.cpp qbutton_nonmac.cpp qprogressindicatorspinning_nonmac.cpp + RESOURCES += qsearchfield_nonmac.qrc qprogressindicatorspinning_nonmac.qrc +} diff --git a/README.md b/README.md new file mode 100644 index 000000000..3d37b6a27 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# Qocoa +Qocoa is a collection of Qt wrappers for OSX's Cocoa widgets. + +## Features +- basic fallback to sensible Qt types on non-OSX platforms +- shared class headers which expose no implementation details +- typical Qt signal/slot-based API +- trivial to import into projects (class header/implementation, [single shared global header](https://github.com/mikemcquaid/Qocoa/blob/master/qocoa_mac.h)) + +## Building +``` +git clone git://github.com/mikemcquaid/Qocoa.git +cd Qocoa +qmake # or cmake . +make +``` + +## Status +Qocoa classes are currently provided for NSButton, a spinning NSProgressIndicator and NSSearchField. There is a [TODO list](https://github.com/mikemcquaid/Qocoa/blob/master/TODO.md) for classes I hope to implement. + +## Usage +For each class you want to use copy the [`qocoa_mac.h`](https://github.com/mikemcquaid/Qocoa/blob/master/qocoa_mac.h), `$CLASS.h`, `$CLASS_mac.*` and `$CLASS_nonmac.*` files into your source tree and add them to your buildsystem. Examples are provided for [CMake](https://github.com/mikemcquaid/Qocoa/blob/master/CMakeLists.txt) and [QMake](https://github.com/mikemcquaid/Qocoa/blob/master/Qocoa.pro). + +## Contact +[Mike McQuaid](mailto:mike@mikemcquaid.com) + +## License +Qocoa is licensed under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). +The full license text is available in [LICENSE.txt](https://github.com/mikemcquaid/Qocoa/blob/master/LICENSE.txt). + +Magnifier and EditClear icons taken from [QtCreator](http://qt-project.org/) and are licensed under the [LGPL](http://www.gnu.org/copyleft/lesser.html). + +Other icons are taken from the [Oxygen Project](http://www.oxygen-icons.org/) and are licensed under the [Creative Commons Attribution-ShareAlike 3.0 License](http://creativecommons.org/licenses/by-sa/3.0/). + +## Gallery +![Qocoa Gallery](https://github.com/mikemcquaid/Qocoa/raw/master/gallery.png) diff --git a/TODO.md b/TODO.md new file mode 100644 index 000000000..45972bafa --- /dev/null +++ b/TODO.md @@ -0,0 +1,13 @@ +Widgets I hope to implement (or at least investigate): + +- NSTokenField +- NSSegmentedControl +- NSLevelIndicator +- NSPathControl +- NSSlider (Circular) +- NSSplitView +- NSTextFinder +- NSOutlineView in an NSScrollView (Source List) +- NSDrawer +- PDFView +- WebView diff --git a/gallery.cpp b/gallery.cpp new file mode 100644 index 000000000..210821ebd --- /dev/null +++ b/gallery.cpp @@ -0,0 +1,75 @@ +#include "gallery.h" + +#include + +#include "qsearchfield.h" +#include "qbutton.h" +#include "qprogressindicatorspinning.h" + +Gallery::Gallery(QWidget *parent) : QWidget(parent) +{ + setWindowTitle("Qocoa Gallery"); + QVBoxLayout *layout = new QVBoxLayout(this); + + QSearchField *searchField = new QSearchField(this); + layout->addWidget(searchField); + + QSearchField *searchFieldPlaceholder = new QSearchField(this); + searchFieldPlaceholder->setPlaceholderText("Placeholder text"); + layout->addWidget(searchFieldPlaceholder); + + QButton *roundedButton = new QButton(this, QButton::Rounded); + roundedButton->setText("Button"); + layout->addWidget(roundedButton); + + QButton *regularSquareButton = new QButton(this, QButton::RegularSquare); + regularSquareButton->setText("Button"); + layout->addWidget(regularSquareButton); + + QButton *disclosureButton = new QButton(this, QButton::Disclosure); + layout->addWidget(disclosureButton); + + QButton *shadowlessSquareButton = new QButton(this, QButton::ShadowlessSquare); + shadowlessSquareButton->setText("Button"); + layout->addWidget(shadowlessSquareButton); + + QButton *circularButton = new QButton(this, QButton::Circular); + layout->addWidget(circularButton); + + QButton *textureSquareButton = new QButton(this, QButton::TexturedSquare); + textureSquareButton->setText("Textured Button"); + layout->addWidget(textureSquareButton); + + QButton *helpButton = new QButton(this, QButton::HelpButton); + layout->addWidget(helpButton); + + QButton *smallSquareButton = new QButton(this, QButton::SmallSquare); + smallSquareButton->setText("Gradient Button"); + layout->addWidget(smallSquareButton); + + QButton *texturedRoundedButton = new QButton(this, QButton::TexturedRounded); + texturedRoundedButton->setText("Round Textured"); + layout->addWidget(texturedRoundedButton); + + QButton *roundedRectangleButton = new QButton(this, QButton::RoundRect); + roundedRectangleButton->setText("Rounded Rect Button"); + layout->addWidget(roundedRectangleButton); + + QButton *recessedButton = new QButton(this, QButton::Recessed); + recessedButton->setText("Recessed Button"); + layout->addWidget(recessedButton); + + QButton *roundedDisclosureButton = new QButton(this, QButton::RoundedDisclosure); + layout->addWidget(roundedDisclosureButton); + +#ifdef __MAC_10_7 + QButton *inlineButton = new QButton(this, QButton::Inline); + inlineButton->setText("Inline Button"); + layout->addWidget(inlineButton); +#endif + + + QProgressIndicatorSpinning *progressIndicatorSpinning = new QProgressIndicatorSpinning(this); + progressIndicatorSpinning->animate(); + layout->addWidget(progressIndicatorSpinning); +} diff --git a/gallery.h b/gallery.h new file mode 100644 index 000000000..1e83bad94 --- /dev/null +++ b/gallery.h @@ -0,0 +1,14 @@ +#ifndef GALLERY_H +#define GALLERY_H + +#include + +class Gallery : public QWidget +{ + Q_OBJECT + +public: + explicit Gallery(QWidget *parent = 0); +}; + +#endif // WIDGET_H diff --git a/gallery.png b/gallery.png new file mode 100644 index 0000000000000000000000000000000000000000..7a2736ff572491af1fefbbface2742caceabd6e3 GIT binary patch literal 42195 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%0DbY5)JT{pQruVuz)6KWO5uY(p-#)v2|KD7@ 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 + +#include "gallery.h" + +int main(int argc, char *argv[]) +{ + QApplication application(argc, argv); + + Gallery gallery; + gallery.show(); + + return application.exec(); +} diff --git a/qbutton.h b/qbutton.h new file mode 100644 index 000000000..93e598f80 --- /dev/null +++ b/qbutton.h @@ -0,0 +1,49 @@ +#ifndef QBUTTON_H +#define QBUTTON_H + +#include +#include + +class QButtonPrivate; +class QButton : public QWidget +{ + Q_OBJECT +public: + // Matches NSBezelStyle + enum BezelStyle { + Rounded = 1, + RegularSquare = 2, + Disclosure = 5, + ShadowlessSquare = 6, + Circular = 7, + TexturedSquare = 8, + HelpButton = 9, + SmallSquare = 10, + TexturedRounded = 11, + RoundRect = 12, + Recessed = 13, + RoundedDisclosure = 14, +#ifdef __MAC_10_7 + Inline = 15 +#endif + }; + + explicit QButton(QWidget *parent, BezelStyle bezelStyle = Rounded); + +public slots: + void setText(const QString &text); + void setImage(const QPixmap &image); + void setChecked(bool checked); + +public: + void setCheckable(bool checkable); + bool isChecked(); + +signals: + void clicked(bool checked = false); + +private: + friend class QButtonPrivate; + QPointer pimpl; +}; +#endif // QBUTTON_H diff --git a/qbutton_mac.mm b/qbutton_mac.mm new file mode 100644 index 000000000..15490e453 --- /dev/null +++ b/qbutton_mac.mm @@ -0,0 +1,229 @@ +/* +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "qbutton.h" + +#include "qocoa_mac.h" + +#import "Foundation/NSAutoreleasePool.h" +#import "AppKit/NSButton.h" +#import "AppKit/NSFont.h" + +class QButtonPrivate : public QObject +{ +public: + QButtonPrivate(QButton *qButton, NSButton *nsButton, QButton::BezelStyle bezelStyle) + : QObject(qButton), qButton(qButton), nsButton(nsButton) + { + switch(bezelStyle) { + case QButton::Disclosure: + case QButton::Circular: +#ifdef __MAC_10_7 + case QButton::Inline: +#endif + case QButton::RoundedDisclosure: + case QButton::HelpButton: + [nsButton setTitle:@""]; + default: + break; + } + + NSFont* font = 0; + switch(bezelStyle) { + case QButton::RoundRect: + font = [NSFont fontWithName:@"Lucida Grande" size:12]; + break; + + case QButton::Recessed: + font = [NSFont fontWithName:@"Lucida Grande Bold" size:12]; + break; + +#ifdef __MAC_10_7 + case QButton::Inline: + font = [NSFont boldSystemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; + break; +#endif + + default: + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; + break; + } + [nsButton setFont:font]; + + switch(bezelStyle) { + case QButton::Rounded: + qButton->setMinimumWidth(40); + qButton->setFixedHeight(24); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + break; + case QButton::RegularSquare: + case QButton::TexturedSquare: + qButton->setMinimumSize(14, 23); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + break; + case QButton::ShadowlessSquare: + qButton->setMinimumSize(5, 25); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + break; + case QButton::SmallSquare: + qButton->setMinimumSize(4, 21); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + break; + case QButton::TexturedRounded: + qButton->setMinimumSize(10, 22); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + break; + case QButton::RoundRect: + case QButton::Recessed: + qButton->setMinimumWidth(16); + qButton->setFixedHeight(18); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + break; + case QButton::Disclosure: + qButton->setMinimumWidth(13); + qButton->setFixedHeight(13); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + break; + case QButton::Circular: + qButton->setMinimumSize(16, 16); + qButton->setMaximumHeight(40); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + break; + case QButton::HelpButton: + case QButton::RoundedDisclosure: + qButton->setMinimumWidth(22); + qButton->setFixedHeight(22); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + break; +#ifdef __MAC_10_7 + case QButton::Inline: + qButton->setMinimumWidth(10); + qButton->setFixedHeight(16); + qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + break; +#endif + } + + switch(bezelStyle) { + case QButton::Recessed: + [nsButton setButtonType:NSPushOnPushOffButton]; + case QButton::Disclosure: + [nsButton setButtonType:NSOnOffButton]; + default: + [nsButton setButtonType:NSMomentaryPushInButton]; + } + + [nsButton setBezelStyle:bezelStyle]; + } + + void clicked() + { + emit qButton->clicked(qButton->isChecked()); + } + + ~QButtonPrivate() { + [[nsButton target] release]; + [nsButton setTarget:nil]; + } + + QButton *qButton; + NSButton *nsButton; +}; + +@interface QButtonTarget : NSObject +{ +@public + QPointer pimpl; +} +-(void)clicked; +@end + +@implementation QButtonTarget +-(void)clicked { + Q_ASSERT(pimpl); + if (pimpl) + pimpl->clicked(); +} +@end + +QButton::QButton(QWidget *parent, BezelStyle bezelStyle) : QWidget(parent) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSButton *button = [[NSButton alloc] init]; + pimpl = new QButtonPrivate(this, button, bezelStyle); + + QButtonTarget *target = [[QButtonTarget alloc] init]; + target->pimpl = pimpl; + [button setTarget:target]; + + [button setAction:@selector(clicked)]; + + setupLayout(button, this); + + [button release]; + + [pool drain]; +} + +void QButton::setText(const QString &text) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pimpl->nsButton setTitle:fromQString(text)]; + [pool drain]; +} + +void QButton::setImage(const QPixmap &image) +{ + Q_ASSERT(pimpl); + if (pimpl) + [pimpl->nsButton setImage:fromQPixmap(image)]; +} + +void QButton::setChecked(bool checked) +{ + Q_ASSERT(pimpl); + if (pimpl) + [pimpl->nsButton setState:checked]; +} + +void QButton::setCheckable(bool checkable) +{ + const NSInteger cellMask = checkable ? NSChangeBackgroundCellMask : NSNoCellMask; + + Q_ASSERT(pimpl); + if (pimpl) + [[pimpl->nsButton cell] setShowsStateBy:cellMask]; +} + +bool QButton::isChecked() +{ + Q_ASSERT(pimpl); + if (!pimpl) + return false; + + return [pimpl->nsButton state]; +} diff --git a/qbutton_nonmac.cpp b/qbutton_nonmac.cpp new file mode 100644 index 000000000..0a79e2baf --- /dev/null +++ b/qbutton_nonmac.cpp @@ -0,0 +1,89 @@ +/* +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "qbutton.h" + +#include +#include +#include +#include + +class QButtonPrivate : public QObject +{ +public: + QButtonPrivate(QButton *button, QAbstractButton *abstractButton) + : QObject(button), abstractButton(abstractButton) {} + QPointer abstractButton; +}; + +QButton::QButton(QWidget *parent, BezelStyle) : QWidget(parent) +{ + QAbstractButton *button = 0; + if (qobject_cast(parent)) + button = new QToolButton(this); + else + button = new QPushButton(this); + connect(button, SIGNAL(clicked()), + this, SIGNAL(clicked())); + pimpl = new QButtonPrivate(this, button); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(button); +} + +void QButton::setText(const QString &text) +{ + Q_ASSERT(pimpl); + if (pimpl) + pimpl->abstractButton->setText(text); +} + +void QButton::setImage(const QPixmap &image) +{ + Q_ASSERT(pimpl); + if (pimpl) + pimpl->abstractButton->setIcon(image); +} + +void QButton::setChecked(bool checked) +{ + Q_ASSERT(pimpl); + if (pimpl) + pimpl->abstractButton->setChecked(checked); +} + +void QButton::setCheckable(bool checkable) +{ + Q_ASSERT(pimpl); + if (pimpl) + pimpl->abstractButton->setCheckable(checkable); +} + +bool QButton::isChecked() +{ + Q_ASSERT(pimpl); + if (!pimpl) + return false; + + return pimpl->abstractButton->isChecked(); +} diff --git a/qocoa_mac.h b/qocoa_mac.h new file mode 100644 index 000000000..f8307e912 --- /dev/null +++ b/qocoa_mac.h @@ -0,0 +1,63 @@ +/* +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + +static inline NSString* fromQString(const QString &string) +{ + const QByteArray utf8 = string.toUtf8(); + const char* cString = utf8.constData(); + return [[NSString alloc] initWithUTF8String:cString]; +} + +static inline QString toQString(NSString *string) +{ + if (!string) + return QString(); + return QString::fromUtf8([string UTF8String]); +} + +static inline NSImage* fromQPixmap(const QPixmap &pixmap) +{ +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) + CGImageRef cgImage = pixmap.toMacCGImageRef(); +#else + CGImageRef cgImage = QtMac::toCGImageRef(pixmap); +#endif + return [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; +} + +static inline void setupLayout(NSView *cocoaView, QWidget *parent) +{ + parent->setAttribute(Qt::WA_NativeWindow); + QVBoxLayout *layout = new QVBoxLayout(parent); + layout->setMargin(0); + layout->addWidget(new QMacCocoaViewContainer(cocoaView, parent)); +} diff --git a/qprogressindicatorspinning.h b/qprogressindicatorspinning.h new file mode 100644 index 000000000..ae40a92a2 --- /dev/null +++ b/qprogressindicatorspinning.h @@ -0,0 +1,29 @@ +#ifndef QPROGRESSINDICATORSPINNING_H +#define QPROGRESSINDICATORSPINNING_H + +#include +#include + +class QProgressIndicatorSpinningPrivate; +class QProgressIndicatorSpinning : public QWidget +{ + Q_OBJECT +public: + // Matches NSProgressIndicatorThickness + enum Thickness { + Default = 14, + Small = 10, + Large = 18, + Aqua = 12 + }; + + explicit QProgressIndicatorSpinning(QWidget *parent, + Thickness thickness = Default); +public slots: + void animate(bool animate = true); +private: + friend class QProgressIndicatorSpinningPrivate; + QPointer pimpl; +}; + +#endif // QPROGRESSINDICATORSPINNING_H diff --git a/qprogressindicatorspinning_mac.mm b/qprogressindicatorspinning_mac.mm new file mode 100644 index 000000000..c67c7c567 --- /dev/null +++ b/qprogressindicatorspinning_mac.mm @@ -0,0 +1,70 @@ +/* +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "qprogressindicatorspinning.h" + +#include "qocoa_mac.h" + +#import "Foundation/NSAutoreleasePool.h" +#import "AppKit/NSProgressIndicator.h" + +class QProgressIndicatorSpinningPrivate : public QObject +{ +public: + QProgressIndicatorSpinningPrivate(QProgressIndicatorSpinning *qProgressIndicatorSpinning, + NSProgressIndicator *nsProgressIndicator) + : QObject(qProgressIndicatorSpinning), nsProgressIndicator(nsProgressIndicator) {} + + NSProgressIndicator *nsProgressIndicator; +}; + +QProgressIndicatorSpinning::QProgressIndicatorSpinning(QWidget *parent, + Thickness thickness) + : QWidget(parent) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSProgressIndicator *progress = [[NSProgressIndicator alloc] init]; + [progress setStyle:NSProgressIndicatorSpinningStyle]; + + pimpl = new QProgressIndicatorSpinningPrivate(this, progress); + + setupLayout(progress, this); + + setFixedSize(thickness, thickness); + + [progress release]; + + [pool drain]; +} + +void QProgressIndicatorSpinning::animate(bool animate) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + if (animate) + [pimpl->nsProgressIndicator startAnimation:nil]; + else + [pimpl->nsProgressIndicator stopAnimation:nil]; +} diff --git a/qprogressindicatorspinning_nonmac.cpp b/qprogressindicatorspinning_nonmac.cpp new file mode 100644 index 000000000..6cbded6c1 --- /dev/null +++ b/qprogressindicatorspinning_nonmac.cpp @@ -0,0 +1,72 @@ +/* +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "qprogressindicatorspinning.h" + +#include +#include +#include + +class QProgressIndicatorSpinningPrivate : public QObject +{ +public: + QProgressIndicatorSpinningPrivate(QProgressIndicatorSpinning *qProgressIndicatorSpinning, + QMovie *movie) + : QObject(qProgressIndicatorSpinning), movie(movie) {} + + QPointer movie; +}; + +QProgressIndicatorSpinning::QProgressIndicatorSpinning(QWidget *parent, + Thickness thickness) + : QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + + QSize size(thickness, thickness); + QMovie *movie = new QMovie(this); + movie->setFileName(":/Qocoa/qprogressindicatorspinning_nonmac.gif"); + movie->setScaledSize(size); + // Roughly match OSX speed. + movie->setSpeed(200); + pimpl = new QProgressIndicatorSpinningPrivate(this, movie); + + QLabel *label = new QLabel(this); + label->setMovie(movie); + + layout->addWidget(label); + setFixedSize(size); +} + + +void QProgressIndicatorSpinning::animate(bool animate) +{ + Q_ASSERT(pimpl && pimpl->movie); + if (!(pimpl && pimpl->movie)) + return; + + if (animate) + pimpl->movie->start(); + else + pimpl->movie->stop(); +} diff --git a/qprogressindicatorspinning_nonmac.gif b/qprogressindicatorspinning_nonmac.gif new file mode 100644 index 0000000000000000000000000000000000000000..3288d1035d70bb86517e2c233f1a904e41f06b29 GIT binary patch literal 3208 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 i)SWB5u7y|&#=&jWN literal 0 HcmV?d00001 diff --git a/qprogressindicatorspinning_nonmac.qrc b/qprogressindicatorspinning_nonmac.qrc new file mode 100644 index 000000000..108c78ec1 --- /dev/null +++ b/qprogressindicatorspinning_nonmac.qrc @@ -0,0 +1,5 @@ + + + qprogressindicatorspinning_nonmac.gif + + diff --git a/qsearchfield.h b/qsearchfield.h new file mode 100644 index 000000000..5abf4986a --- /dev/null +++ b/qsearchfield.h @@ -0,0 +1,48 @@ +#ifndef QSEARCHFIELD_H +#define QSEARCHFIELD_H + +#include +#include +#include + +class QSearchFieldPrivate; +class QSearchField : public QWidget +{ + Q_OBJECT + + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true); + Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText); + +public: + explicit QSearchField(QWidget *parent); + + QString text() const; + QString placeholderText() const; + void setFocus(Qt::FocusReason); + void setMenu(QMenu *menu); + +public slots: + void setText(const QString &text); + void setPlaceholderText(const QString &text); + void clear(); + void selectAll(); + void setFocus(); + +signals: + void textChanged(const QString &text); + void editingFinished(); + void returnPressed(); + +private slots: + void popupMenu(); + +protected: + void changeEvent(QEvent*); + void resizeEvent(QResizeEvent*); + +private: + friend class QSearchFieldPrivate; + QPointer pimpl; +}; + +#endif // QSEARCHFIELD_H diff --git a/qsearchfield_mac.mm b/qsearchfield_mac.mm new file mode 100644 index 000000000..345ee7848 --- /dev/null +++ b/qsearchfield_mac.mm @@ -0,0 +1,262 @@ +/* +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "qsearchfield.h" + +#include "qocoa_mac.h" + +#import "Foundation/NSAutoreleasePool.h" +#import "Foundation/NSNotification.h" +#import "AppKit/NSSearchField.h" + +#include +#include + +#define KEYCODE_A 0 +#define KEYCODE_X 7 +#define KEYCODE_C 8 +#define KEYCODE_V 9 + +class QSearchFieldPrivate : public QObject +{ +public: + QSearchFieldPrivate(QSearchField *qSearchField, NSSearchField *nsSearchField) + : QObject(qSearchField), qSearchField(qSearchField), nsSearchField(nsSearchField) {} + + void textDidChange(const QString &text) + { + if (qSearchField) + emit qSearchField->textChanged(text); + } + + void textDidEndEditing() + { + if (qSearchField) + emit qSearchField->editingFinished(); + } + + void returnPressed() + { + if (qSearchField) + emit qSearchField->returnPressed(); + } + + QPointer qSearchField; + NSSearchField *nsSearchField; +}; + +@interface QSearchFieldDelegate : NSObject +{ +@public + QPointer pimpl; +} +-(void)controlTextDidChange:(NSNotification*)notification; +-(void)controlTextDidEndEditing:(NSNotification*)notification; +@end + +@implementation QSearchFieldDelegate +-(void)controlTextDidChange:(NSNotification*)notification { + Q_ASSERT(pimpl); + if (pimpl) + pimpl->textDidChange(toQString([[notification object] stringValue])); +} + +-(void)controlTextDidEndEditing:(NSNotification*)notification { + Q_UNUSED(notification); + // No Q_ASSERT here as it is called on destruction. + if (pimpl) + pimpl->textDidEndEditing(); + + if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement) + pimpl->returnPressed(); +} +@end + +@interface QocoaSearchField : NSSearchField +-(BOOL)performKeyEquivalent:(NSEvent*)event; +@end + +@implementation QocoaSearchField +-(BOOL)performKeyEquivalent:(NSEvent*)event { + if ([event type] == NSKeyDown && [event modifierFlags] & NSCommandKeyMask) + { + const unsigned short keyCode = [event keyCode]; + if (keyCode == KEYCODE_A) + { + [self performSelector:@selector(selectText:)]; + return YES; + } + else if (keyCode == KEYCODE_C) + { + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(toQString([self stringValue])); + return YES; + } + else if (keyCode == KEYCODE_V) + { + QClipboard* clipboard = QApplication::clipboard(); + [self setStringValue:fromQString(clipboard->text())]; + return YES; + } + else if (keyCode == KEYCODE_X) + { + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(toQString([self stringValue])); + [self setStringValue:@""]; + return YES; + } + } + + return NO; +} +@end + +QSearchField::QSearchField(QWidget *parent) : QWidget(parent) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSSearchField *search = [[QocoaSearchField alloc] init]; + + QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init]; + pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search); + [search setDelegate:delegate]; + + setupLayout(search, this); + + setFixedHeight(24); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + [search release]; + + [pool drain]; +} + +void QSearchField::setMenu(QMenu *menu) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) + NSMenu *nsMenu = menu->macMenu(); +#else + NSMenu *nsMenu = menu->toNSMenu(); +#endif + + [[pimpl->nsSearchField cell] setSearchMenuTemplate:nsMenu]; +} + +void QSearchField::popupMenu() +{ +} + +void QSearchField::setText(const QString &text) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pimpl->nsSearchField setStringValue:fromQString(text)]; + [pool drain]; +} + +void QSearchField::setPlaceholderText(const QString &text) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [[pimpl->nsSearchField cell] setPlaceholderString:fromQString(text)]; + [pool drain]; +} + +void QSearchField::clear() +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + [pimpl->nsSearchField setStringValue:@""]; + emit textChanged(QString()); +} + +void QSearchField::selectAll() +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + [pimpl->nsSearchField performSelector:@selector(selectText:)]; +} + +QString QSearchField::text() const +{ + Q_ASSERT(pimpl); + if (!pimpl) + return QString(); + + return toQString([pimpl->nsSearchField stringValue]); +} + +QString QSearchField::placeholderText() const +{ + Q_ASSERT(pimpl); + if (!pimpl) + return QString(); + + return toQString([[pimpl->nsSearchField cell] placeholderString]); +} + +void QSearchField::setFocus(Qt::FocusReason) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + if ([pimpl->nsSearchField acceptsFirstResponder]) + [[pimpl->nsSearchField window] makeFirstResponder: pimpl->nsSearchField]; +} + +void QSearchField::setFocus() +{ + setFocus(Qt::OtherFocusReason); +} + +void QSearchField::changeEvent(QEvent* event) +{ + if (event->type() == QEvent::EnabledChange) { + Q_ASSERT(pimpl); + if (!pimpl) + return; + + const bool enabled = isEnabled(); + [pimpl->nsSearchField setEnabled: enabled]; + } + QWidget::changeEvent(event); +} + +void QSearchField::resizeEvent(QResizeEvent *resizeEvent) +{ + QWidget::resizeEvent(resizeEvent); +} diff --git a/qsearchfield_nonmac.cpp b/qsearchfield_nonmac.cpp new file mode 100644 index 000000000..d3315b853 --- /dev/null +++ b/qsearchfield_nonmac.cpp @@ -0,0 +1,256 @@ +/* +Copyright (C) 2011 by Mike McQuaid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "qsearchfield.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +class QSearchFieldPrivate : public QObject +{ +public: + QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton, QToolButton *searchButton) + : QObject(searchField), lineEdit(lineEdit), clearButton(clearButton), searchButton(searchButton) {} + + int lineEditFrameWidth() const { + return lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + } + + int clearButtonPaddedWidth() const { + return clearButton->width() + lineEditFrameWidth() * 2; + } + + int clearButtonPaddedHeight() const { + return clearButton->height() + lineEditFrameWidth() * 2; + } + + int searchButtonPaddedWidth() const { + return searchButton->width() + lineEditFrameWidth() * 2; + } + + int searchButtonPaddedHeight() const { + return searchButton->height() + lineEditFrameWidth() * 2; + } + + QPointer lineEdit; + QPointer clearButton; + QPointer searchButton; + QPointer searchMenu; +}; + +QSearchField::QSearchField(QWidget *parent) : QWidget(parent) +{ + QLineEdit *lineEdit = new QLineEdit(this); + connect(lineEdit, SIGNAL(textChanged(QString)), + this, SIGNAL(textChanged(QString))); + connect(lineEdit, SIGNAL(editingFinished()), + this, SIGNAL(editingFinished())); + connect(lineEdit, SIGNAL(returnPressed()), + this, SIGNAL(returnPressed())); + connect(lineEdit, SIGNAL(textChanged(QString)), + this, SLOT(setText(QString))); + + int iconsize = style()->pixelMetric(QStyle::PM_SmallIconSize); + QToolButton *clearButton = new QToolButton(this); + QIcon clearIcon = QIcon::fromTheme(QLatin1String("edit-clear"), + QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_clear.png"))); + clearButton->setIcon(clearIcon); + clearButton->setIconSize(QSize(iconsize, iconsize)); + clearButton->setFixedSize(QSize(iconsize, iconsize)); + clearButton->setStyleSheet("border: none;"); + clearButton->hide(); + connect(clearButton, SIGNAL(clicked()), this, SLOT(clear())); + + QToolButton *searchButton = new QToolButton(this); + QIcon searchIcon = QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier.png")); + searchButton->setIcon(searchIcon); + searchButton->setIconSize(QSize(iconsize, iconsize)); + searchButton->setFixedSize(QSize(iconsize, iconsize)); + searchButton->setStyleSheet("border: none;"); + searchButton->setPopupMode(QToolButton::InstantPopup); + searchButton->setEnabled(false); + connect(searchButton, SIGNAL(clicked()), this, SLOT(popupMenu())); + + pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton, searchButton); + + lineEdit->setStyleSheet(QString("QLineEdit { padding-left: %1px; padding-right: %2px; } ") + .arg(pimpl->searchButtonPaddedWidth()) + .arg(pimpl->clearButtonPaddedWidth())); + const int width = qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth() + pimpl->searchButtonPaddedWidth()); + const int height = qMax(lineEdit->minimumSizeHint().height(), + qMax(pimpl->clearButtonPaddedHeight(), + pimpl->searchButtonPaddedHeight())); + lineEdit->setMinimumSize(width, height); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(lineEdit); +} + +void QSearchField::setMenu(QMenu *menu) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + pimpl->searchMenu = menu; + + QIcon searchIcon = menu ? QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier_menu.png")) + : QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier.png")); + pimpl->searchButton->setIcon(searchIcon); + pimpl->searchButton->setEnabled(isEnabled() && menu); +} + +void QSearchField::popupMenu() +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + if (pimpl->searchMenu) { + const QRect screenRect = qApp->desktop()->availableGeometry(pimpl->searchButton); + const QSize sizeHint = pimpl->searchMenu->sizeHint(); + const QRect rect = pimpl->searchButton->rect(); + const int x = pimpl->searchButton->isRightToLeft() + ? rect.right() - sizeHint.width() + : rect.left(); + const int y = pimpl->searchButton->mapToGlobal(QPoint(0, rect.bottom())).y() + sizeHint.height() <= screenRect.height() + ? rect.bottom() + : rect.top() - sizeHint.height(); + QPoint point = pimpl->searchButton->mapToGlobal(QPoint(x, y)); + point.rx() = qMax(screenRect.left(), qMin(point.x(), screenRect.right() - sizeHint.width())); + point.ry() += 1; + + pimpl->searchMenu->popup(point); + } +} + +void QSearchField::changeEvent(QEvent* event) +{ + if (event->type() == QEvent::EnabledChange) { + Q_ASSERT(pimpl); + if (!pimpl) + return; + + const bool enabled = isEnabled(); + pimpl->searchButton->setEnabled(enabled && pimpl->searchMenu); + pimpl->lineEdit->setEnabled(enabled); + pimpl->clearButton->setEnabled(enabled); + } + QWidget::changeEvent(event); +} + +void QSearchField::setText(const QString &text) +{ + Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit); + if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) + return; + + pimpl->clearButton->setVisible(!text.isEmpty()); + + if (text != this->text()) + pimpl->lineEdit->setText(text); +} + +void QSearchField::setPlaceholderText(const QString &text) +{ + Q_ASSERT(pimpl && pimpl->lineEdit); + if (!(pimpl && pimpl->lineEdit)) + return; + +#if QT_VERSION >= 0x040700 + pimpl->lineEdit->setPlaceholderText(text); +#endif +} + +void QSearchField::clear() +{ + Q_ASSERT(pimpl && pimpl->lineEdit); + if (!(pimpl && pimpl->lineEdit)) + return; + + pimpl->lineEdit->clear(); +} + +void QSearchField::selectAll() +{ + Q_ASSERT(pimpl && pimpl->lineEdit); + if (!(pimpl && pimpl->lineEdit)) + return; + + pimpl->lineEdit->selectAll(); +} + +QString QSearchField::text() const +{ + Q_ASSERT(pimpl && pimpl->lineEdit); + if (!(pimpl && pimpl->lineEdit)) + return QString(); + + return pimpl->lineEdit->text(); +} + +QString QSearchField::placeholderText() const { + Q_ASSERT(pimpl && pimpl->lineEdit); + if (!(pimpl && pimpl->lineEdit)) + return QString(); + +#if QT_VERSION >= 0x040700 + return pimpl->lineEdit->placeholderText(); +#else + return QString(); +#endif +} + +void QSearchField::setFocus(Qt::FocusReason reason) +{ + Q_ASSERT(pimpl && pimpl->lineEdit); + if (pimpl && pimpl->lineEdit) + pimpl->lineEdit->setFocus(reason); +} + +void QSearchField::setFocus() +{ + setFocus(Qt::OtherFocusReason); +} + +void QSearchField::resizeEvent(QResizeEvent *resizeEvent) +{ + Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit); + if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) + return; + + QWidget::resizeEvent(resizeEvent); + const int x = width() - pimpl->clearButtonPaddedWidth(); + const int y = (height() - pimpl->clearButton->height())/2; + pimpl->clearButton->move(x, y); + + pimpl->searchButton->move(pimpl->lineEditFrameWidth() * 2, + (height() - pimpl->searchButton->height())/2); +} diff --git a/qsearchfield_nonmac.qrc b/qsearchfield_nonmac.qrc new file mode 100644 index 000000000..68b570d5b --- /dev/null +++ b/qsearchfield_nonmac.qrc @@ -0,0 +1,7 @@ + + + qsearchfield_nonmac_clear.png + qsearchfield_nonmac_magnifier_menu.png + qsearchfield_nonmac_magnifier.png + + diff --git a/qsearchfield_nonmac_clear.png b/qsearchfield_nonmac_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..ec52c41bc2fbba0bcc2b30a96267d73be240dc13 GIT binary patch literal 736 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&N| z?e4a&{t=l;KZ@#lZz|Hym$rElN9 z{W|EB?)lGFP90(np`pUh@BB^L_@k=0c=BKM1=nBi4fXn~xzuNB5Qky~V?s~j#t0j! zWV`tI`1;DLKkU1DCMyHZr=3BX{p{0>#s-i zAN~-#_+mxy`s+9E-%mH2t+>=B`|PV%TGrOqK5D`(0+%eOZ;4vFf3wbSHO3}|8(fDC zdKY!<-D}&|*Qe3dbop{HLtlS?WOVdl%i~wCie9^QC2BWo%KC=BYf?)^7GLbRdpGvh zTQhZabp{nrr+LqN+?1yTWvrcf{<$mzqr%c0&7~89f~Kh+emLP}iPt0*70*K@R;d;; zLDN)&yyDWL8H5geuWb?dvCm)Tc*ffLPt~cZtoOecp3_aAE^YB#?VRPBtw##aBp58X znKS9RW#zofIcAbPY)1-vwu(KMIk)qqP(bL_y<5eSdG6*-H}RG1KmO%+?XSOfk3Y^Z z@qJmgTOxVGwV=?ee=i;D?d?t1d@4WhxoKX0zGhd`=FP@7=bbtF{pYXK=xREB+Pmid zaf#0sv(MVu+1S)Xt9|_N;ltW%zxEdU+1uMMo}$#H#BgfU5eetDVTV8OS-yPva{lMf zpU3~3cx3nP-8sd@o4?fBb2csbm^>xE|Jj`CIp?3(@9nDp>BG*>{@PI>hf~q2BJOmx q<)*c7_RgHWUR+#Ua{uOi%qtsz=xT&@Ug{G}nwTs%f>}*LAwdqV)+$%27ay??kF)!x> z(H%=?WSM7g+F)&P)}ZFke~CYfOnkRz&SEH#X@C7Si$UW3(a%5kusS+Ov@vYS^}hdo zN@}LWdzahWcE;#gJ4{Q}IeqA1x<#L|mu8EAwf0hpHpY*2ZK;tQigrc`{@-l)*P1TN ze79!nvG0FvE9a%>ZI^z%tH^3DL&mJOb+0wL9(_#^alQSw&fTl?^)4GZeulo|%AS+< zEbD$;A$?p>Q?+tl{h6Ojonx>6*Q#5+YSr8GLLXR~LISJoHt_^AFfcH9y85}Sb4q9e E0Ic(R)c^nh literal 0 HcmV?d00001 diff --git a/qsearchfield_nonmac_magnifier_menu.png b/qsearchfield_nonmac_magnifier_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..0e652c945e4287939e4787cd02c891c50238c64a GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0y~yU=U|H*Y zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU<~(kaSYKoKetb@+bB__b$K?>Kx2T7m|ux4E$y!2)N8Kx}&f8Yprw{|C|E3ceXN5E9KVj ziqX5VO?UZa&V~{z-@S3+A1mg}Us7|wp6&j3$^PR(T2ohqXfdq0o?W(E_HJId>g1E> zRiA(UDXBKO^GK3m)Y@yeFP2z6E!%zZWyzK0lk^W8RNN?y)j9oWs$^SZYUG>mzw`eb zJru%qAaA`uOd$4rf!t>#wKE zcB}F@uez$maQf+_vuTG5EJC8PrFz?fyiV5GEf3JR@c#Q$uEP@)I3#%3iY#Odd?)9a zo&H$CqA>mR#k}pIN)vz7&z*8QRkYXbVcq`AufHw{TkW~|rpWov0u$qZW^aw^e7$SN svXdDmK`TSL;=NrqOmixzErGKgAQT^mY3=9kmp00i_>zopr03+PLga7~l literal 0 HcmV?d00001