1
2#include <QtCore>
3#include <QtGui>
4#include <QtWidgets>
5#include <QMacNativeWidget>
6
7#include <Cocoa/Cocoa.h>
8#include <objc/runtime.h>
9#include <CoreServices/CoreServices.h>
10
11#include <klfdefs.h>
12
13#include <klfsidewidget.h>
14#include "klfsidewidget_p.h"
15
16
17
18inline NSRectEdge nsEdgeForQtEdge(Qt::DockWidgetArea edge)
19{
20  switch (edge) {
21  case Qt::LeftDockWidgetArea:     return NSMinXEdge;
22  case Qt::RightDockWidgetArea:    return NSMaxXEdge;
23  case Qt::TopDockWidgetArea:      return NSMinYEdge;
24  case Qt::BottomDockWidgetArea:   return NSMaxYEdge;
25  default:
26    qWarning()<<KLF_FUNC_NAME<<": Invalid Qt::DockWidgetArea edge: " << edge << "\n";
27  }
28  return NSMaxXEdge; // by default
29}
30
31inline NSSize nsSizeForQSize(QSize sz)
32{
33  NSSize nsz;
34  nsz.width = sz.width();
35  nsz.height = sz.height();
36  return nsz;
37}
38
39
40
41struct KLFDrawerSideWidgetManagerPrivate
42{
43  KLF_PRIVATE_HEAD(KLFDrawerSideWidgetManager)
44  {
45    nsdrawer = NULL;
46    sideWidget = NULL;
47    nativeWidget = NULL;
48    layout = NULL;
49    openEdge = Qt::RightDockWidgetArea;
50  }
51
52  NSDrawer * nsdrawer;
53  QWidget * sideWidget;
54  QMacNativeWidget * nativeWidget;
55  QLayout * layout;
56
57  Qt::DockWidgetArea openEdge;
58};
59
60KLFDrawerSideWidgetManager::KLFDrawerSideWidgetManager(QWidget *parentWidget, QWidget *sideWidget, QObject *parent)
61  : KLFSideWidgetManagerBase(parentWidget, sideWidget, false, parent)
62{
63  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
64  klfDbg("parentW=" << parentWidget << ", sidewidget=" << sideWidget << ", parent=" << parent) ;
65
66  KLF_INIT_PRIVATE(KLFDrawerSideWidgetManager) ;
67
68  NSView * nswinview = reinterpret_cast<NSView*>(parentWidget->window()->winId());
69
70  NSSize csz = nsSizeForQSize(sideWidget->sizeHint());
71  d->nsdrawer = [[NSDrawer alloc] initWithContentSize:csz preferredEdge:NSMaxXEdge];
72  [d->nsdrawer setParentWindow:[nswinview window]];
73  NSView *contentView = [d->nsdrawer contentView];
74
75  d->nsdrawer.minContentSize = nsSizeForQSize(sideWidget->minimumSizeHint());
76  d->nsdrawer.maxContentSize = nsSizeForQSize(QSize(32767,32767));
77
78  // inspired by http://doc.qt.io/qt-5/qmacnativewidget.html
79
80  d->nativeWidget = new QMacNativeWidget(contentView);
81  d->nativeWidget->move(0, 0);
82  //d->nativeWidget->setPalette(QPalette(Qt::red));
83  d->nativeWidget->setAutoFillBackground(true);
84  //d->nativeWidget->setMinimumSize(sideWidget->minimumSizeHint());
85  d->layout = new QVBoxLayout();
86  d->layout->setMargin(0);
87  d->sideWidget = sideWidget;
88  d->sideWidget->setParent(d->nativeWidget);
89  d->sideWidget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
90  d->layout->addWidget(sideWidget);
91  d->nativeWidget->setLayout(d->layout);
92
93  NSView *nativeWidgetView = d->nativeWidget->nativeView();
94  [contentView setAutoresizesSubviews:YES];
95  [nativeWidgetView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
96  [nativeWidgetView setAutoresizesSubviews:YES];
97  NSView *sideWidgetView = reinterpret_cast<NSView *>(d->sideWidget->winId());
98  [sideWidgetView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
99
100  // Add the nativeWidget to the window.
101  [contentView addSubview:nativeWidgetView positioned:NSWindowAbove relativeTo:nil];
102  d->nativeWidget->show();
103
104  d->sideWidget->show();
105
106  NSRect frame = [contentView frame];
107  d->nativeWidget->resize(QSize(frame.size.width, frame.size.height));
108
109  setOurParentWidget(parentWidget);
110  setSideWidget(sideWidget);
111}
112
113KLFDrawerSideWidgetManager::~KLFDrawerSideWidgetManager()
114{
115  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
116
117  KLF_DELETE_PRIVATE ;
118}
119
120// protected
121void KLFDrawerSideWidgetManager::newSideWidgetSet(QWidget *oldw, QWidget *neww)
122{
123  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
124
125  if (oldw != NULL) {
126    d->layout->removeWidget(oldw);
127  }
128  if (neww != NULL) {
129    d->sideWidget = neww;
130    d->sideWidget->setParent(d->nativeWidget);
131    d->sideWidget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
132    d->layout->addWidget(neww);
133    NSView *sideWidgetView = reinterpret_cast<NSView *>(d->sideWidget->winId());
134    [sideWidgetView setAutoresizingMask:NSViewWidthSizable];
135    d->sideWidget->show();
136    NSRect frame = [[d->nsdrawer contentView] frame];
137    d->nativeWidget->resize(QSize(frame.size.width, frame.size.height));
138  }
139}
140
141// protected
142void KLFDrawerSideWidgetManager::newParentWidgetSet(QWidget */*oldp*/, QWidget *newWidget)
143{
144  if (d->sideWidget->parentWidget() != newWidget) {
145    d->sideWidget->setParent(newWidget);
146  }
147}
148
149bool KLFDrawerSideWidgetManager::sideWidgetVisible() const
150{
151  NSInteger s = [d->nsdrawer state];
152  return (s == NSDrawerOpenState || s == NSDrawerOpeningState);
153}
154
155void KLFDrawerSideWidgetManager::showSideWidget(bool show)
156{
157  KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
158
159  if (show == sideWidgetVisible()) {
160    klfDbg("show == sideWidgetVisible() == " << show);
161    return;
162  }
163
164  klfDbg("show=" << show << "; sideWidgetVisible()=" << sideWidgetVisible());
165
166  if (show) {
167    [d->nsdrawer openOnEdge:nsEdgeForQtEdge(d->openEdge)];
168  } else {
169    [d->nsdrawer close];
170  }
171
172  emit sideWidgetShown(show);
173}
174
175bool KLFDrawerSideWidgetManager::showHideIsAnimating()
176{
177  NSInteger s = [d->nsdrawer state];
178  return (s == NSDrawerOpeningState || s == NSDrawerClosingState);
179}
180
181
182KLF_DEFINE_PROPERTY_GET(KLFDrawerSideWidgetManager, Qt::DockWidgetArea, openEdge) ;
183
184void KLFDrawerSideWidgetManager::setOpenEdge(Qt::DockWidgetArea edge)
185{
186  d->openEdge = edge;
187}
188
189
190
191