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  * $Revision$ *
45  * $LastChangedBy$ *
46  * $Date$ *
47  * *
48  \*===========================================================================*/
49 
50 //=============================================================================
51 //
52 // CLASS QtSlideWindow
53 //
54 //=============================================================================
55 
56 
57 //== GLOBAL DEFINITIONS=========================================================
58 
59 #define BACKGROUND_RED 0xff
60 #define BACKGROUND_GREEN 0xff
61 #define BACKGROUND_BLUE 0xff
62 #define BACKGROUND_ALPHA 0xcf
63 
64 #define SLIDE_DURATION 300
65 #define WAIT_UNTIL_SLIDE_DOWN 500
66 
67 //== INCLUDES =================================================================
68 
70 
71 #include <QPainter>
72 #include <QGraphicsSceneMouseEvent>
73 #include <QGraphicsScene>
74 #include <QGraphicsView>
75 #include <QDialog>
76 #include <QVBoxLayout>
77 
78 #include "QtSlideWindow.hh"
79 #include "QtGraphicsButton.hh"
80 
81 //== IMPLEMENTATION ==========================================================
82 
83 QtSlideWindow::QtSlideWindow(QString _name, QGraphicsItem *_parent) :
84  QGraphicsProxyWidget(_parent),
85  name_(_name),
86  mainWidget_(0),
87  autohideButton_(0),
88  detachButton_(0),
89  dialog_(0),
90  down_(false),
91  animating_(false),
92  timer_(0) {
93 
94  setCacheMode(QGraphicsItem::DeviceCoordinateCache);
95  setWindowFrameMargins(2, 15, 2, 2);
96  setZValue(2.0);
97 
98  QImage autohide(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "button-autohide.png");
99  QImage detach(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "button-detach.png");
100 
101  autohideButton_ = new QtGraphicsButton(autohide, this, 12, 12);
102  detachButton_ = new QtGraphicsButton(detach, this, 12, 12);
103 
104  autohideButton_->setCheckable(true);
105  autohideButton_->setChecked(true);
106  autohideButton_->setPos(geometry().width() - 12, -13);
107  detachButton_->setPos(geometry().width() - 25, -13);
108 
109  connect(detachButton_, SIGNAL(pressed()), this, SLOT(detachPressed()));
110  connect(autohideButton_, SIGNAL(pressed()), this, SLOT(autohidePressed()));
111 
112  // Create animation object
113  animation_ = new QPropertyAnimation(this, "pos");
114  animation_->setDuration(SLIDE_DURATION);
115  connect(animation_, SIGNAL(finished()), this, SLOT(animationFinished()));
116 
117  // Create timer
118  timer_ = new QTimer();
119  timer_->setSingleShot(true);
120 
121  // Wait some milliseconds before starting the actual slide down animation
122  connect(timer_, SIGNAL(timeout()), this, SLOT(startSlideDownAnimation()));
123 
124  // Hide widget
125  hide();
126 
127  setAcceptHoverEvents(true);
128 
130 }
131 
132 //-----------------------------------------------------------------------------
133 
134 void QtSlideWindow::attachWidget(QWidget *_m) {
135 
136  if (!_m)
137  return;
138 
139  mainWidget_ = _m;
140  mainWidget_->setParent(0);
141 
142  if (autohideButton_->isChecked()) {
143  setWidget(mainWidget_);
144  setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
145 
146  down_ = true;
147 
148  show();
149  }
150  updateGeometry();
151 }
152 
153 //-----------------------------------------------------------------------------
154 
156 
157  setWidget(0);
158  hide();
159 
160  if (mainWidget_) {
161  mainWidget_->setParent(0);
162  mainWidget_ = 0;
163  }
164 
165  if (dialog_) {
166  disconnect (dialog_, SIGNAL(finished (int)), this, SLOT(dialogClosed ()));
167  dialog_->close();
168  delete dialog_;
169  dialog_ = 0;
170  }
171 }
172 
173 //-----------------------------------------------------------------------------
174 
175 void QtSlideWindow::paintWindowFrame(QPainter *_painter, const QStyleOptionGraphicsItem* /*_option*/, QWidget* /*_widget*/) {
176 
177  int w = geometry().width();
178  int h = geometry().height();
179 
180  _painter->setRenderHint(QPainter::Antialiasing, true);
181  _painter->setBrush(QBrush(QColor(BACKGROUND_RED, BACKGROUND_GREEN, BACKGROUND_BLUE, BACKGROUND_ALPHA)));
182  _painter->setPen(QColor(BACKGROUND_RED / 4, BACKGROUND_GREEN / 4, BACKGROUND_BLUE / 4, BACKGROUND_ALPHA));
183  _painter->drawRoundedRect(-2, -15, w + 4, h + 40, 4, 4);
184 
185  _painter->setPen(Qt::SolidLine);
186 
187  _painter->drawText(2, -13, w - 4, 11, Qt::AlignCenter, name_);
188 }
189 
190 //-----------------------------------------------------------------------------
191 
193 
194  if(_e->type() == QEvent::GraphicsSceneMousePress || _e->type() == QEvent::GraphicsSceneMouseRelease) {
195  QGraphicsSceneMouseEvent *ge = dynamic_cast<QGraphicsSceneMouseEvent*> (_e);
196  if(windowFrameSectionAt(ge->pos()) != Qt::TopSection) {
197  _e->accept();
198  return false;
199  }
200  }
201 
202  return QGraphicsProxyWidget::windowFrameEvent(_e);
203 }
204 
205 //-----------------------------------------------------------------------------
206 
207 Qt::WindowFrameSection QtSlideWindow::windowFrameSectionAt(const QPointF &_pos) const {
208 
209  if (_pos.x() >= 2 && _pos.x() < geometry().width() - 2 - (13 * 2) && _pos.y() >= -15 && _pos.y() <= -10) {
210  return Qt::TopSection;
211  }
212 
213  return Qt::NoSection;
214 }
215 
216 //-----------------------------------------------------------------------------
217 
218 void QtSlideWindow::hoverEnterEvent(QGraphicsSceneHoverEvent *) {
219 
220  // Stop slide down action after timeout if the cursor
221  // re-enters the logger within the timeout interval
222  if(timer_->isActive()) {
223  timer_->stop();
224  return;
225  }
226 
227  // Don't do anything if animation is currently in progress
228  if(animating_) return;
229 
230  if (autohideButton_->isChecked() && down_) {
231  slideUp();
232  }
233  if (!mainWidget_->isVisible()) {
234  setWidget(mainWidget_);
235  setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
236  show();
237  }
238 }
239 
240 //-----------------------------------------------------------------------------
241 
242 void QtSlideWindow::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
243 
244  // Don't do anything if animation is currently in progress
245  if(animating_) return;
246 
247  if (autohideButton_->isChecked() && !down_) {
248  slideDown();
249  }
250 }
251 
252 //-----------------------------------------------------------------------------
253 
254 void QtSlideWindow::resizeEvent(QGraphicsSceneResizeEvent *_event) {
255 
256  QGraphicsProxyWidget::resizeEvent(_event);
257 }
258 
259 //-----------------------------------------------------------------------------
260 
261 void QtSlideWindow::moveEvent(QGraphicsSceneMoveEvent *_event) {
262 
263  QGraphicsProxyWidget::moveEvent(_event);
264 }
265 
266 //-----------------------------------------------------------------------------
267 
269 
270  setWidget(0);
271 
272  dialog_ = new QDialog(0, Qt::Window);
273  dialog_->setWindowTitle(name_);
274  dialog_->setLayout(new QVBoxLayout);
275  dialog_->resize(mainWidget_->size());
276  dialog_->layout()->addWidget(mainWidget_);
277 
278  if (scene() && scene()->views()[0] && scene()->views()[0]->window()) {
279  QWidget *w = scene()->views()[0]->window();
280  int x = (w->width() - mainWidget_->width()) / 2;
281  x += w->x();
282  x = qMax(0, x);
283  int y = (w->height() - mainWidget_->height()) / 2;
284  y += w->y();
285  y = qMax(0, y);
286  dialog_->move(x, y);
287  }
288 
289  hide();
290 
291  dialog_->show();
292  connect (dialog_, SIGNAL(finished (int)), this, SLOT(dialogClosed ()));
293 }
294 
295 //-----------------------------------------------------------------------------
296 
298 
299  dialog_ = 0;
300  mainWidget_->setParent(0);
301 
302  setWidget(mainWidget_);
303  setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
304 
305  show();
306 
307  updateGeometry();
308 }
309 
310 //-----------------------------------------------------------------------------
311 
313 
314  if(!autohideButton_->isChecked() && down_) {
315  slideUp();
316  }
317 }
318 
319 //-----------------------------------------------------------------------------
320 
322 
323  startP_.setX(10);
324  startP_.setY(parentWidget()->geometry().height() - geometry().height());
325 
326  endP_.setX(10);
327  endP_.setY(parentWidget()->geometry().height() - (size().height() - geometry().height()));
328 }
329 
330 //-----------------------------------------------------------------------------
331 
333 
334  animating_ = false;
335 
336  // If we reached up position,
337  // check if the mouse is still inside (could leave in between as we block the leave event
338  // when animating to avoid flickering
339  // If mouse is not inside anymore, we start the countdown for slideDown
340  if ( !down_ && !isUnderMouse() )
341  timer_->start(WAIT_UNTIL_SLIDE_DOWN);
342 }
343 
344 //-----------------------------------------------------------------------------
345 
347 
348  if(!widget()) return;
349 
351 
352  down_ = false;
353  animating_ = true;
354 
355  animation_->setStartValue(endP_);
356  animation_->setEndValue(startP_);
357 
358  animation_->start();
359 }
360 
361 //-----------------------------------------------------------------------------
362 
364 
365  if(!widget()) return;
366 
368 
369  timer_->start(WAIT_UNTIL_SLIDE_DOWN);
370 }
371 
372 //-----------------------------------------------------------------------------
373 
375 
376  down_ = true;
377  animating_ = true;
378 
379  animation_->setStartValue(startP_);
380  animation_->setEndValue(endP_);
381 
382  animation_->start();
383 }
384 
385 //-----------------------------------------------------------------------------
386 
388 
389  if (parentWidget() && widget()) {
390 
392 
393  resize(parentWidget()->geometry().width() - 20, widget()->size().height());
394 
395  if(down_) {
396  setPos(endP_);
397  } else {
398  setPos(startP_);
399  }
400 
401  if (autohideButton_) {
402  autohideButton_->setPos(geometry().width() - 12, -13);
403  }
404  if (detachButton_) {
405  detachButton_->setPos(geometry().width() - 25, -13);
406  }
407  }
408 }
409 
410 //-----------------------------------------------------------------------------
411 
412 void QtSlideWindow::saveState(QSettings &_settings) {
413 
414  _settings.setValue("AutoHide", autohideButton_->isChecked());
415  _settings.setValue("Detached", (dialog_ != 0));
416  _settings.setValue("WidgedGeometry", (mainWidget_) ? mainWidget_->saveGeometry() : QByteArray());
417  _settings.setValue("DialogGeometry", (dialog_) ? dialog_->saveGeometry() : QByteArray());
418 }
419 
420 //-----------------------------------------------------------------------------
421 
422 void QtSlideWindow::restoreState(QSettings &_settings) {
423 
424  autohideButton_->setChecked(_settings.value("AutoHide", autohideButton_->isChecked()).toBool());
425 
426  if (_settings.value("Detached", false).toBool() && !dialog_ && mainWidget_) {
427  detachPressed();
428  }
429 
430  if (mainWidget_) {
431  mainWidget_->restoreGeometry(_settings.value("WidgedGeometry").toByteArray());
432  }
433 
434  if (autohideButton_->isChecked()) {
435 
436  } else {
437  if (!mainWidget_->isVisible()) {
438  setWidget(mainWidget_);
439  setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
440  show();
441  }
442  }
443 
444  if (dialog_)
445  dialog_->restoreGeometry(_settings.value("DialogGeometry").toByteArray());
446 }
447 
448 //=============================================================================
449 
virtual bool windowFrameEvent(QEvent *_e)
track frame events
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *_event)
hove event tracking
void updateGeometry()
recalculate geometry
virtual void paintWindowFrame(QPainter *_painter, const QStyleOptionGraphicsItem *_option, QWidget *_widget=0)
paints decoration
void restoreState(QSettings &_settings)
restores the state
void startSlideDownAnimation()
Start actual slide down.
void detachWidget()
detach child widget
virtual Qt::WindowFrameSection windowFrameSectionAt(const QPointF &_pos) const
categorize frame area
void dialogClosed()
detached dialog closed
QtSlideWindow(QString _name=0, QGraphicsItem *_parent=0)
void updateParentGeometry()
Call this to correctly set start and ending positions.
void attachWidget(QWidget *_m)
attach a child widget
void slideUp()
Slide widget up.
void autohidePressed()
autohide button presed
void saveState(QSettings &_settings)
saves the current state
bool isChecked() const
returns button checked state
virtual void resizeEvent(QGraphicsSceneResizeEvent *_event)
size & position event tracking
void detachPressed()
detach button pressed
void slideDown()
Slide widget down.
void animationFinished()
Slot is called whenever the animation is finished.
void setCheckable(bool _value)
makes the button checkable
void setChecked(bool _value)
sets button checked state