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
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
75QtSlideWindow::QtSlideWindow(const 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
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
123}
124
125//-----------------------------------------------------------------------------
126
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 }
144}
145
146//-----------------------------------------------------------------------------
147
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
168void 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
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
198Qt::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
209void 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
233void 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
245void QtSlideWindow::resizeEvent(QGraphicsSceneResizeEvent *_event) {
246
247 QGraphicsProxyWidget::resizeEvent(_event);
248}
249
250//-----------------------------------------------------------------------------
251
252void QtSlideWindow::moveEvent(QGraphicsSceneMoveEvent *_event) {
253
254 QGraphicsProxyWidget::moveEvent(_event);
255}
256
257//-----------------------------------------------------------------------------
258
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
289
290 dialog_ = 0;
291 mainWidget_->setParent(0);
292
293 setWidget(mainWidget_);
294 setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
295
296 show();
297
299}
300
301//-----------------------------------------------------------------------------
302
304
305 if(!autohideButton_->isChecked() && down_) {
306 slideUp();
307 }
308}
309
310//-----------------------------------------------------------------------------
311
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
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
338
339 if(!widget()) return;
340
342
343 down_ = false;
344 animating_ = true;
345
346 animation_->setStartValue(endP_);
347 animation_->setEndValue(startP_);
348
349 animation_->start();
350}
351
352//-----------------------------------------------------------------------------
353
355
356 if(!widget()) return;
357
359
360 timer_->start(WAIT_UNTIL_SLIDE_DOWN);
361}
362
363//-----------------------------------------------------------------------------
364
366
367 down_ = true;
368 animating_ = true;
369
370 animation_->setStartValue(startP_);
371 animation_->setEndValue(endP_);
372
373 animation_->start();
374}
375
376//-----------------------------------------------------------------------------
377
379
380 if (parentWidget() && widget()) {
381
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
403void 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
413void QtSlideWindow::restoreState(QSettings &_settings) {
414
415 autohideButton_->setChecked(_settings.value("AutoHide", autohideButton_->isChecked()).toBool());
416
417 if (_settings.value("Detached", false).toBool() && !dialog_ && mainWidget_) {
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
void setChecked(bool _value)
sets button checked state
void setCheckable(bool _value)
makes the button checkable
bool isChecked() const
returns button checked state
void slideUp()
Slide widget up.
QPointF endP_
Ending position (for animation)
virtual bool windowFrameEvent(QEvent *_e)
track frame events
void updateGeometry()
recalculate geometry
QWidget * mainWidget_
child widget
QPointF startP_
Starting position (for animation)
void detachWidget()
detach child widget
void autohidePressed()
autohide button presed
QString name_
name
void updateParentGeometry()
Call this to correctly set start and ending positions.
bool animating_
Is widget animating in this moment?
QPropertyAnimation * animation_
Animation object.
void dialogClosed()
detached dialog closed
QtSlideWindow(const QString &_name=0, QGraphicsItem *_parent=0)
void restoreState(QSettings &_settings)
restores the state
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *_event)
hove event tracking
virtual Qt::WindowFrameSection windowFrameSectionAt(const QPointF &_pos) const
categorize frame area
void attachWidget(QWidget *_m)
attach a child widget
void saveState(QSettings &_settings)
saves the current state
bool down_
Track if widget is at bottom position.
QDialog * dialog_
detached dialog
QTimer * timer_
Wait some milliseconds before sliding widget down.
void animationFinished()
Slot is called whenever the animation is finished.
void startSlideDownAnimation()
Start actual slide down.
virtual void resizeEvent(QGraphicsSceneResizeEvent *_event)
size & position event tracking
void slideDown()
Slide widget down.
const int fontHeight_
height of the default font
QtGraphicsButton * autohideButton_
buttons
virtual void paintWindowFrame(QPainter *_painter, const QStyleOptionGraphicsItem *_option, QWidget *_widget=0)
paints decoration
void detachPressed()
detach button pressed