Developer Documentation

QtSlideWindow.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42 //=============================================================================
43 //
44 // CLASS QtSlideWindow
45 //
46 //=============================================================================
47
48
49 //== GLOBAL DEFINITIONS=========================================================
50
51 #define BACKGROUND_RED 0xff
52 #define BACKGROUND_GREEN 0xff
53 #define BACKGROUND_BLUE 0xff
54 #define BACKGROUND_ALPHA 0xcf
55
56 #define SLIDE_DURATION 300
57 #define WAIT_UNTIL_SLIDE_DOWN 500
58
59 //== INCLUDES =================================================================
60
61 #include <OpenFlipper/common/GlobalOptions.hh>
62
63 #include <QPainter>
64 #include <QGraphicsSceneMouseEvent>
65 #include <QGraphicsScene>
66 #include <QGraphicsView>
67 #include <QDialog>
68 #include <QVBoxLayout>
69
70 #include "QtSlideWindow.hh"
71 #include "QtGraphicsButton.hh"
72
73 //== IMPLEMENTATION ==========================================================
74
75 QtSlideWindow::QtSlideWindow(QString _name, QGraphicsItem *_parent) :
76 QGraphicsProxyWidget(_parent),
77 name_(_name),
78 mainWidget_(0),
79 autohideButton_(0),
80 detachButton_(0),
81 dialog_(0),
82 down_(false),
83 animating_(false),
84 timer_(0),
85 fontHeight_(QFontMetrics(QFont()).height()){
86
87 setCacheMode(QGraphicsItem::DeviceCoordinateCache);
88 setWindowFrameMargins(2, 15, 2, 2);
89 setZValue(2.0);
90
91 QImage autohide(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "button-autohide.png");
92 QImage detach(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "button-detach.png");
93
94 autohideButton_ = new QtGraphicsButton(autohide, this, 12, 12);
95 detachButton_ = new QtGraphicsButton(detach, this, 12, 12);
96
97 autohideButton_->setCheckable(true);
98 autohideButton_->setChecked(true);
99 autohideButton_->setPos(geometry().width() - 12, -13);
100 detachButton_->setPos(geometry().width() - 25, -13);
101
102 connect(detachButton_, SIGNAL(pressed()), this, SLOT(detachPressed()));
103 connect(autohideButton_, SIGNAL(pressed()), this, SLOT(autohidePressed()));
104
105 // Create animation object
106 animation_ = new QPropertyAnimation(this, "pos");
107 animation_->setDuration(SLIDE_DURATION);
108 connect(animation_, SIGNAL(finished()), this, SLOT(animationFinished()));
109
110 // Create timer
111 timer_ = new QTimer();
112 timer_->setSingleShot(true);
113
114 // Wait some milliseconds before starting the actual slide down animation
115 connect(timer_, SIGNAL(timeout()), this, SLOT(startSlideDownAnimation()));
116
117 // Hide widget
118 hide();
119
120 setAcceptHoverEvents(true);
121
122 updateParentGeometry();
123 }
124
125 //-----------------------------------------------------------------------------
126
127 void QtSlideWindow::attachWidget(QWidget *_m) {
128
129 if (!_m)
130 return;
131
132 mainWidget_ = _m;
133 mainWidget_->setParent(0);
134
135 if (autohideButton_->isChecked()) {
136 setWidget(mainWidget_);
137 setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
138
139 down_ = true;
140
141 show();
142 }
143 updateGeometry();
144 }
145
146 //-----------------------------------------------------------------------------
147
148 void QtSlideWindow::detachWidget() {
149
150 setWidget(0);
151 hide();
152
153 if (mainWidget_) {
154 mainWidget_->setParent(0);
155 mainWidget_ = 0;
156 }
157
158 if (dialog_) {
159 disconnect (dialog_, SIGNAL(finished (int)), this, SLOT(dialogClosed ()));
160 dialog_->close();
161 delete dialog_;
162 dialog_ = 0;
163 }
164 }
165
166 //-----------------------------------------------------------------------------
167
168 void QtSlideWindow::paintWindowFrame(QPainter *_painter, const QStyleOptionGraphicsItem* /*_option*/, QWidget* /*_widget*/) {
169
170 int w = geometry().width();
171 int h = geometry().height();
172
173 _painter->setRenderHint(QPainter::Antialiasing, true);
174 _painter->setBrush(QPalette{}.window());
175 _painter->setPen(QPalette{}.windowText().color());
176 _painter->drawRoundedRect(-2, -4-fontHeight_, w + 4, h + 40, 4, 4);
177
178 _painter->drawText(2, -2-fontHeight_, w - 4, fontHeight_, Qt::AlignCenter, name_);
179 }
180
181 //-----------------------------------------------------------------------------
182
183 bool QtSlideWindow::windowFrameEvent(QEvent *_e) {
184
185 if(_e->type() == QEvent::GraphicsSceneMousePress || _e->type() == QEvent::GraphicsSceneMouseRelease) {
186 QGraphicsSceneMouseEvent *ge = dynamic_cast<QGraphicsSceneMouseEvent*> (_e);
187 if(windowFrameSectionAt(ge->pos()) != Qt::TopSection) {
188 _e->accept();
189 return false;
190 }
191 }
192
193 return QGraphicsProxyWidget::windowFrameEvent(_e);
194 }
195
196 //-----------------------------------------------------------------------------
197
198 Qt::WindowFrameSection QtSlideWindow::windowFrameSectionAt(const QPointF &_pos) const {
199
200 if (_pos.x() >= 2 && _pos.x() < geometry().width() - 2 - (13 * 2) && _pos.y() >= -15 && _pos.y() <= -10) {
201 return Qt::TopSection;
202 }
203
204 return Qt::NoSection;
205 }
206
207 //-----------------------------------------------------------------------------
208
209 void QtSlideWindow::hoverEnterEvent(QGraphicsSceneHoverEvent *) {
210
211 // Stop slide down action after timeout if the cursor
212 // re-enters the logger within the timeout interval
213 if(timer_->isActive()) {
214 timer_->stop();
215 return;
216 }
217
218 // Don't do anything if animation is currently in progress
219 if(animating_) return;
220
221 if (autohideButton_->isChecked() && down_) {
222 slideUp();
223 }
224 if (!mainWidget_->isVisible()) {
225 setWidget(mainWidget_);
226 setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
227 show();
228 }
229 }
230
231 //-----------------------------------------------------------------------------
232
233 void QtSlideWindow::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
234
235 // Don't do anything if animation is currently in progress
236 if(animating_) return;
237
238 if (autohideButton_->isChecked() && !down_) {
239 slideDown();
240 }
241 }
242
243 //-----------------------------------------------------------------------------
244
245 void QtSlideWindow::resizeEvent(QGraphicsSceneResizeEvent *_event) {
246
247 QGraphicsProxyWidget::resizeEvent(_event);
248 }
249
250 //-----------------------------------------------------------------------------
251
252 void QtSlideWindow::moveEvent(QGraphicsSceneMoveEvent *_event) {
253
254 QGraphicsProxyWidget::moveEvent(_event);
255 }
256
257 //-----------------------------------------------------------------------------
258
259 void QtSlideWindow::detachPressed() {
260
261 setWidget(0);
262
263 dialog_ = new QDialog(0, Qt::Window);
264 dialog_->setWindowTitle(name_);
265 dialog_->setLayout(new QVBoxLayout);
266 dialog_->resize(mainWidget_->size());
267 dialog_->layout()->addWidget(mainWidget_);
268
269 if (scene() && scene()->views()[0] && scene()->views()[0]->window()) {
270 QWidget *w = scene()->views()[0]->window();
271 int x = (w->width() - mainWidget_->width()) / 2;
272 x += w->x();
273 x = qMax(0, x);
274 int y = (w->height() - mainWidget_->height()) / 2;
275 y += w->y();
276 y = qMax(0, y);
277 dialog_->move(x, y);
278 }
279
280 hide();
281
282 dialog_->show();
283 connect (dialog_, SIGNAL(finished (int)), this, SLOT(dialogClosed ()));
284 }
285
286 //-----------------------------------------------------------------------------
287
288 void QtSlideWindow::dialogClosed() {
289
290 dialog_ = 0;
291 mainWidget_->setParent(0);
292
293 setWidget(mainWidget_);
294 setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
295
296 show();
297
298 updateGeometry();
299 }
300
301 //-----------------------------------------------------------------------------
302
303 void QtSlideWindow::autohidePressed() {
304
305 if(!autohideButton_->isChecked() && down_) {
306 slideUp();
307 }
308 }
309
310 //-----------------------------------------------------------------------------
311
312 void QtSlideWindow::updateParentGeometry() {
313
314 startP_.setX(10);
315 startP_.setY(parentWidget()->geometry().height() - geometry().height());
316
317 endP_.setX(10);
318 endP_.setY(parentWidget()->geometry().height() - (size().height() - geometry().height()));
319 }
320
321 //-----------------------------------------------------------------------------
322
323 void QtSlideWindow::animationFinished() {
324
325 animating_ = false;
326
327 // If we reached up position,
328 // check if the mouse is still inside (could leave in between as we block the leave event
329 // when animating to avoid flickering
330 // If mouse is not inside anymore, we start the countdown for slideDown
331 if ( !down_ && !isUnderMouse() )
332 timer_->start(WAIT_UNTIL_SLIDE_DOWN);
333 }
334
335 //-----------------------------------------------------------------------------
336
337 void QtSlideWindow::slideUp() {
338
339 if(!widget()) return;
340
341 updateParentGeometry();
342
343 down_ = false;
344 animating_ = true;
345
346 animation_->setStartValue(endP_);
347 animation_->setEndValue(startP_);
348
349 animation_->start();
350 }
351
352 //-----------------------------------------------------------------------------
353
354 void QtSlideWindow::slideDown() {
355
356 if(!widget()) return;
357
358 updateParentGeometry();
359
360 timer_->start(WAIT_UNTIL_SLIDE_DOWN);
361 }
362
363 //-----------------------------------------------------------------------------
364
365 void QtSlideWindow::startSlideDownAnimation() {
366
367 down_ = true;
368 animating_ = true;
369
370 animation_->setStartValue(startP_);
371 animation_->setEndValue(endP_);
372
373 animation_->start();
374 }
375
376 //-----------------------------------------------------------------------------
377
378 void QtSlideWindow::updateGeometry() {
379
380 if (parentWidget() && widget()) {
381
382 updateParentGeometry();
383
384 resize(parentWidget()->geometry().width() - 20, widget()->size().height());
385
386 if(down_) {
387 setPos(endP_);
388 } else {
389 setPos(startP_);
390 }
391
392 if (autohideButton_) {
393 autohideButton_->setPos(geometry().width() - 12, -13);
394 }
395 if (detachButton_) {
396 detachButton_->setPos(geometry().width() - 25, -13);
397 }
398 }
399 }
400
401 //-----------------------------------------------------------------------------
402
403 void QtSlideWindow::saveState(QSettings &_settings) {
404
405 _settings.setValue("AutoHide", autohideButton_->isChecked());
406 _settings.setValue("Detached", (dialog_ != 0));
407 _settings.setValue("WidgedGeometry", (mainWidget_) ? mainWidget_->saveGeometry() : QByteArray());
408 _settings.setValue("DialogGeometry", (dialog_) ? dialog_->saveGeometry() : QByteArray());
409 }
410
411 //-----------------------------------------------------------------------------
412
413 void QtSlideWindow::restoreState(QSettings &_settings) {
414
415 autohideButton_->setChecked(_settings.value("AutoHide", autohideButton_->isChecked()).toBool());
416
417 if (_settings.value("Detached", false).toBool() && !dialog_ && mainWidget_) {
418 detachPressed();
419 }
420
421 if (mainWidget_) {
422 mainWidget_->restoreGeometry(_settings.value("WidgedGeometry").toByteArray());
423 }
424
425 if (autohideButton_->isChecked()) {
426
427 } else {
428 if (!mainWidget_->isVisible()) {
429 setWidget(mainWidget_);
430 setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
431 show();
432 }
433 }
434
435 if (dialog_)
436 dialog_->restoreGeometry(_settings.value("DialogGeometry").toByteArray());
437 }
438
439 //=============================================================================
440
QtGraphicsButton::isChecked
bool isChecked() const
returns button checked state
Definition: QtGraphicsButton.cc:133
QtSlideWindow::detachWidget
void detachWidget()
detach child widget
Definition: QtSlideWindow.cc:148
QtSlideWindow::updateGeometry
void updateGeometry()
recalculate geometry
Definition: QtSlideWindow.cc:378
QtSlideWindow::endP_
QPointF endP_
Ending position (for animation)
Definition: QtSlideWindow.hh:167
QtSlideWindow::resizeEvent
virtual void resizeEvent(QGraphicsSceneResizeEvent *_event)
size & position event tracking
Definition: QtSlideWindow.cc:245
QtSlideWindow::updateParentGeometry
void updateParentGeometry()
Call this to correctly set start and ending positions.
Definition: QtSlideWindow.cc:312
QtSlideWindow::detachPressed
void detachPressed()
detach button pressed
Definition: QtSlideWindow.cc:259
QtSlideWindow::slideDown
void slideDown()
Slide widget down.
Definition: QtSlideWindow.cc:354
QtSlideWindow::dialog_
QDialog * dialog_
detached dialog
Definition: QtSlideWindow.hh:161
QtSlideWindow::hoverEnterEvent
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *_event)
hove event tracking
Definition: QtSlideWindow.cc:209
QtGraphicsButton
Definition: QtGraphicsButton.hh:65
QtGraphicsButton::setChecked
void setChecked(bool _value)
sets button checked state
Definition: QtGraphicsButton.cc:126
GlobalOptions.hh
QtSlideWindow::down_
bool down_
Track if widget is at bottom position.
Definition: QtSlideWindow.hh:170
QtSlideWindow::animationFinished
void animationFinished()
Slot is called whenever the animation is finished.
Definition: QtSlideWindow.cc:323
QtSlideWindow::startSlideDownAnimation
void startSlideDownAnimation()
Start actual slide down.
Definition: QtSlideWindow.cc:365
QtSlideWindow::restoreState
void restoreState(QSettings &_settings)
restores the state
Definition: QtSlideWindow.cc:413
QtSlideWindow::windowFrameEvent
virtual bool windowFrameEvent(QEvent *_e)
track frame events
Definition: QtSlideWindow.cc:183
QtSlideWindow::slideUp
void slideUp()
Slide widget up.
Definition: QtSlideWindow.cc:337
QtSlideWindow::dialogClosed
void dialogClosed()
detached dialog closed
Definition: QtSlideWindow.cc:288
QtSlideWindow::startP_
QPointF startP_
Starting position (for animation)
Definition: QtSlideWindow.hh:164
QtSlideWindow::fontHeight_
const int fontHeight_
height of the default font
Definition: QtSlideWindow.hh:182
QtSlideWindow::saveState
void saveState(QSettings &_settings)
saves the current state
Definition: QtSlideWindow.cc:403
QtSlideWindow::paintWindowFrame
virtual void paintWindowFrame(QPainter *_painter, const QStyleOptionGraphicsItem *_option, QWidget *_widget=0)
paints decoration
Definition: QtSlideWindow.cc:168
QtSlideWindow::windowFrameSectionAt
virtual Qt::WindowFrameSection windowFrameSectionAt(const QPointF &_pos) const
categorize frame area
Definition: QtSlideWindow.cc:198
QtSlideWindow::attachWidget
void attachWidget(QWidget *_m)
attach a child widget
Definition: QtSlideWindow.cc:127
QtSlideWindow::autohideButton_
QtGraphicsButton * autohideButton_
buttons
Definition: QtSlideWindow.hh:157
QtSlideWindow::QtSlideWindow
QtSlideWindow(QString _name=0, QGraphicsItem *_parent=0)
Definition: QtSlideWindow.cc:75
QtSlideWindow::animation_
QPropertyAnimation * animation_
Animation object.
Definition: QtSlideWindow.hh:173
QtSlideWindow::autohidePressed
void autohidePressed()
autohide button presed
Definition: QtSlideWindow.cc:303
QtSlideWindow::timer_
QTimer * timer_
Wait some milliseconds before sliding widget down.
Definition: QtSlideWindow.hh:179
QtSlideWindow::animating_
bool animating_
Is widget animating in this moment?
Definition: QtSlideWindow.hh:176
QtSlideWindow::name_
QString name_
name
Definition: QtSlideWindow.hh:151
QtGraphicsButton::setCheckable
void setCheckable(bool _value)
makes the button checkable
Definition: QtGraphicsButton.cc:119
QtSlideWindow::mainWidget_
QWidget * mainWidget_
child widget
Definition: QtSlideWindow.hh:154