Vuo  2.0.2
VuoPopover.cc
Go to the documentation of this file.
1 
10 #include "VuoPopover.hh"
11 
12 #ifdef __APPLE__
13 #include <objc/runtime.h>
14 #endif
15 
19 VuoPopover::VuoPopover(QWidget *parent) :
20  QWidget(parent)
21 {
22 }
23 
25 
32 QPainterPath VuoPopover::getPopoverPath(Qt::AnchorPoint arrowSide, int arrowPixelsFromTopOrLeft)
33 {
34  int cornerRadius = 8;
35 
36  QPainterPath path;
37 
38  bool omitArrow = ((arrowPixelsFromTopOrLeft < cornerRadius) ||
39  (arrowPixelsFromTopOrLeft > (((arrowSide == Qt::AnchorTop) ||
40  (arrowSide == Qt::AnchorBottom))?
41  width() :
42  height())
43  - cornerRadius));
44 
45  if (arrowSide == Qt::AnchorTop)
46  {
47  path.moveTo(arrowPixelsFromTopOrLeft-popoverArrowHalfWidth,popoverArrowHalfWidth);
48 
49  if (!omitArrow)
50  path.lineTo(arrowPixelsFromTopOrLeft,0);
51 
52  path.lineTo(arrowPixelsFromTopOrLeft+popoverArrowHalfWidth,popoverArrowHalfWidth);
53  path.lineTo(width()-cornerRadius,popoverArrowHalfWidth);
54  path.cubicTo(width(),popoverArrowHalfWidth, width(),popoverArrowHalfWidth, width(),popoverArrowHalfWidth+cornerRadius);
55  path.lineTo(width(),height()-cornerRadius);
56  path.cubicTo(width(),height(), width(),height(), width()-cornerRadius,height());
57  path.lineTo(cornerRadius,height());
58  path.cubicTo(0,height(), 0,height(), 0,height()-cornerRadius);
59  path.lineTo(0,popoverArrowHalfWidth+cornerRadius);
60  path.cubicTo(0,popoverArrowHalfWidth, 0,popoverArrowHalfWidth, cornerRadius,popoverArrowHalfWidth);
61  path.closeSubpath();
62  }
63  else if (arrowSide == Qt::AnchorRight)
64  {
65  path.moveTo(width()-popoverArrowHalfWidth-cornerRadius,0);
66  path.cubicTo(width()-popoverArrowHalfWidth,0, width()-popoverArrowHalfWidth,0, width()-popoverArrowHalfWidth,cornerRadius);
67  path.lineTo(width()-popoverArrowHalfWidth,arrowPixelsFromTopOrLeft-popoverArrowHalfWidth);
68 
69  if (!omitArrow)
70  path.lineTo(width(),arrowPixelsFromTopOrLeft);
71 
72  path.lineTo(width()-popoverArrowHalfWidth,arrowPixelsFromTopOrLeft+popoverArrowHalfWidth);
73  path.lineTo(width()-popoverArrowHalfWidth,height()-cornerRadius);
74  path.cubicTo(width()-popoverArrowHalfWidth,height(), width()-popoverArrowHalfWidth,height(), width()-popoverArrowHalfWidth-cornerRadius,height());
75  path.lineTo(cornerRadius,height());
76  path.cubicTo(0,height(), 0,height(), 0,height()-cornerRadius);
77  path.lineTo(0,cornerRadius);
78  path.cubicTo(0,0, 0,0, cornerRadius,0);
79  path.closeSubpath();
80  }
81  else if (arrowSide == Qt::AnchorBottom)
82  {
83  path.moveTo(width()-cornerRadius,0);
84  path.cubicTo(width(),0, width(),0, width(),cornerRadius);
85  path.lineTo(width(),height()-popoverArrowHalfWidth-cornerRadius);
86  path.cubicTo(width(),height()-popoverArrowHalfWidth, width(),height()-popoverArrowHalfWidth, width()-cornerRadius,height()-popoverArrowHalfWidth);
87  path.lineTo(arrowPixelsFromTopOrLeft+popoverArrowHalfWidth,height()-popoverArrowHalfWidth);
88 
89  if (!omitArrow)
90  path.lineTo(arrowPixelsFromTopOrLeft,height());
91 
92  path.lineTo(arrowPixelsFromTopOrLeft-popoverArrowHalfWidth,height()-popoverArrowHalfWidth);
93  path.lineTo(cornerRadius,height()-popoverArrowHalfWidth);
94  path.cubicTo(0,height()-popoverArrowHalfWidth, 0,height()-popoverArrowHalfWidth, 0,height()-popoverArrowHalfWidth-cornerRadius);
95  path.lineTo(0,cornerRadius);
96  path.cubicTo(0,0, 0,0, cornerRadius,0);
97  path.closeSubpath();
98  }
99  else if (arrowSide == Qt::AnchorLeft)
100  {
101  path.moveTo(width()-cornerRadius,0);
102  path.cubicTo(width(),0, width(),0, width(),cornerRadius);
103  path.lineTo(width(),height()-cornerRadius);
104  path.cubicTo(width(),height(), width(),height(), width()-cornerRadius,height());
105  path.lineTo(popoverArrowHalfWidth+cornerRadius,height());
106  path.cubicTo(popoverArrowHalfWidth,height(), popoverArrowHalfWidth,height(), popoverArrowHalfWidth,height()-cornerRadius);
107  path.lineTo(popoverArrowHalfWidth,arrowPixelsFromTopOrLeft+popoverArrowHalfWidth);
108 
109  if (!omitArrow)
110  path.lineTo(0,arrowPixelsFromTopOrLeft);
111 
112  path.lineTo(popoverArrowHalfWidth,arrowPixelsFromTopOrLeft-popoverArrowHalfWidth);
113  path.lineTo(popoverArrowHalfWidth,cornerRadius);
114  path.cubicTo(popoverArrowHalfWidth,0, popoverArrowHalfWidth,0, popoverArrowHalfWidth+cornerRadius,0);
115  path.closeSubpath();
116  }
117 
118  return path;
119 }
120 
124 QMargins VuoPopover::getPopoverContentsMargins(Qt::AnchorPoint arrowSide)
125 {
126  return QMargins(
127  5 + (arrowSide==Qt::AnchorLeft ? popoverArrowHalfWidth : 0),
128  5 + (arrowSide==Qt::AnchorTop ? popoverArrowHalfWidth : 0),
129  5 + (arrowSide==Qt::AnchorRight ? popoverArrowHalfWidth : 0),
130  5 + (arrowSide==Qt::AnchorBottom ? popoverArrowHalfWidth : 0)
131  );
132 }
133 
137 void * VuoPopover::getWindowForPopover(QWidget *popoverWidget)
138 {
139  id view = (id)popoverWidget->winId();
140 
141  // window = [view window];
142  Class nsView = (Class)objc_getClass("NSView");
143  SEL windowSEL = sel_registerName("window");
144  Method nsViewWindowMethod = class_getInstanceMethod(nsView, windowSEL);
145  IMP nsViewWindow = method_getImplementation(nsViewWindowMethod);
146  void *window = nsViewWindow(view, method_getName(nsViewWindowMethod));
147 
148  return window;
149 }
150 
156 void VuoPopover::setWindowLevelAndVisibility(bool top, QWidget *popoverWidget)
157 {
158  setWindowLevelForNextUpdate(top, popoverWidget);
159 
160  if (!top)
161  popoverWidget->lower();
162 }
163 
168 void VuoPopover::setWindowLevel(bool top, QWidget *popoverWidget)
169 {
170  setWindowLevelForNextUpdate(top, popoverWidget);
171 
172  if (!top)
173  {
174  // lower()ing forces re-evaluation of the window level, but, unlike raise(),
175  // does not cause the application to receive an ApplicationActivate event in Qt 5.3.
176  popoverWidget->lower();
177 
178  // lower()ing effectively hides the popover; reverse that side effect.
179  popoverWidget->hide();
180  popoverWidget->show();
181  }
182 }
183 
189 void VuoPopover::setWindowLevelForNextUpdate(bool top, QWidget *popoverWidget)
190 {
191  void *window = getWindowForPopover(popoverWidget);
192 
193  // [window setLevel:...];
194  Class nsWindow = (Class)objc_getClass("NSWindow");
195  SEL setLevelSEL = sel_registerName("setLevel:");
196  Method nsWindowSetLevelMethod = class_getInstanceMethod(nsWindow, setLevelSEL);
197  IMP nsWindowSetLevel = method_getImplementation(nsWindowSetLevelMethod);
198  int key;
199  if (top)
200  key = 8; // kCGMainMenuWindowLevelKey
201  else
202  key = 0; // Anything higher than zero seems to float..?
203  nsWindowSetLevel((id)window, method_getName(nsWindowSetLevelMethod), key);
204 }