]> sigrok.org Git - pulseview.git/blobdiff - pv/widgets/popup.cpp
Renamed C++ headers to .hpp
[pulseview.git] / pv / widgets / popup.cpp
index f89e38a6b1b84e3fdc9b923060f31688277c87f1..7143c24a9aba9ce568bc933d3283ee67c648660c 100644 (file)
 
 #include <algorithm>
 
+#include <assert.h>
+
 #include <QtGui>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QLineEdit>
 
-#include "popup.h"
+#include "popup.hpp"
 
-using namespace std;
+using std::max;
+using std::min;
 
 namespace pv {
 namespace widgets {
 
-const unsigned int Popup::ArrowLength = 15;
+const unsigned int Popup::ArrowLength = 10;
 const unsigned int Popup::ArrowOverlap = 3;
-const unsigned int Popup::MarginWidth = 10;
+const unsigned int Popup::MarginWidth = 6;
 
 Popup::Popup(QWidget *parent) :
        QWidget(parent, Qt::Popup | Qt::FramelessWindowHint),
-       _point(),
-       _pos(Left)
+       point_(),
+       pos_(Left)
 {
 }
 
 const QPoint& Popup::point() const
 {
-       return _point;
+       return point_;
 }
 
 Popup::Position Popup::position() const
 {
-       return _pos;
+       return pos_;
 }
 
 void Popup::set_position(const QPoint point, Position pos)
 {
-       _point = point, _pos = pos;
+       point_ = point, pos_ = pos;
 
        setContentsMargins(
                MarginWidth + ((pos == Right) ? ArrowLength : 0),
@@ -62,14 +68,84 @@ void Popup::set_position(const QPoint point, Position pos)
 
 }
 
+bool Popup::eventFilter(QObject *obj, QEvent *evt)
+{
+       QKeyEvent *keyEvent;
+
+       (void)obj;
+
+       if (evt->type() == QEvent::KeyPress) {
+               keyEvent = static_cast<QKeyEvent*>(evt);
+               if (keyEvent->key() == Qt::Key_Enter ||
+                   keyEvent->key() == Qt::Key_Return) {
+                       close();
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+void Popup::show()
+{
+       QLineEdit* le;
+
+       QWidget::show();
+
+       // We want to close the popup when the Enter key was
+       // pressed and the first editable widget had focus.
+       if ((le = this->findChild<QLineEdit*>())) {
+
+               // For combo boxes we need to hook into the parent of
+               // the line edit (i.e. the QComboBox). For edit boxes
+               // we hook into the widget directly.
+               if (le->parent()->metaObject()->className() ==
+                               this->metaObject()->className())
+                       le->installEventFilter(this);
+               else
+                       le->parent()->installEventFilter(this);
+
+               le->selectAll();
+               le->setFocus();
+       }
+}
+
+bool Popup::space_for_arrow() const
+{
+       // Check if there is room for the arrow
+       switch (pos_) {
+       case Right:
+               if (point_.x() > x())
+                       return false;
+               return true;
+
+       case Bottom:
+               if (point_.y() > y())
+                       return false;
+               return true;            
+
+       case Left:
+               if (point_.x() < (x() + width()))
+                       return false;
+               return true;
+
+       case Top:
+               if (point_.y() < (y() + height()))
+                       return false;
+               return true;
+       }
+
+       return true;
+}
+
 QPolygon Popup::arrow_polygon() const
 {
        QPolygon poly;
 
-       const QPoint p = mapFromGlobal(_point);
+       const QPoint p = mapFromGlobal(point_);
        const int l = ArrowLength + ArrowOverlap; 
 
-       switch (_pos)
+       switch (pos_)
         {
        case Right:
                poly << QPoint(p.x() + l, p.y() - l);
@@ -87,7 +163,7 @@ QPolygon Popup::arrow_polygon() const
 
        poly << p;
 
-       switch (_pos)
+       switch (pos_)
         {
        case Right:
        case Bottom:
@@ -114,11 +190,11 @@ QRegion Popup::arrow_region() const
 QRect Popup::bubble_rect() const
 {
        return QRect(
-               QPoint((_pos == Right) ? ArrowLength : 0,
-                       (_pos == Bottom) ? ArrowLength : 0),
-               QSize(width() - ((_pos == Left || _pos == Right) ?
+               QPoint((pos_ == Right) ? ArrowLength : 0,
+                       (pos_ == Bottom) ? ArrowLength : 0),
+               QSize(width() - ((pos_ == Left || pos_ == Right) ?
                                ArrowLength : 0),
-                       height() - ((_pos == Top || _pos == Bottom) ?
+                       height() - ((pos_ == Top || pos_ == Bottom) ?
                                ArrowLength : 0)));
 }
 
@@ -142,24 +218,39 @@ QRegion Popup::bubble_region() const
 
 QRegion Popup::popup_region() const
 {
-       return arrow_region().united(bubble_region());
+       if (space_for_arrow())
+               return arrow_region().united(bubble_region());
+       else
+               return bubble_region();
 }
 
 void Popup::reposition_widget()
 {
        QPoint o;
 
-       if (_pos == Right || _pos == Left)
+       const QRect screen_rect = QApplication::desktop()->availableGeometry(
+               QApplication::desktop()->screenNumber(point_));
+
+       if (pos_ == Right || pos_ == Left)
                o.ry() = -height() / 2;
        else
                o.rx() = -width() / 2;
 
-       if (_pos == Left)
+       if (pos_ == Left)
                o.rx() = -width();
-       else if(_pos == Top)
+       else if(pos_ == Top)
                o.ry() = -height();
 
-       move(_point + o);
+       o += point_;
+       move(max(min(o.x(), screen_rect.right() - width()),
+                       screen_rect.left()),
+               max(min(o.y(), screen_rect.bottom() - height()),
+                       screen_rect.top()));
+}
+
+void Popup::closeEvent(QCloseEvent*)
+{
+       closed();
 }
 
 void Popup::paintEvent(QPaintEvent*)
@@ -170,6 +261,7 @@ void Popup::paintEvent(QPaintEvent*)
        const QColor outline_color(QApplication::palette().color(
                QPalette::Dark));
 
+       // Draw the bubble
        const QRegion b = bubble_region();
        const QRegion bubble_outline = QRegion(rect()).subtracted(
                b.translated(1, 0).intersected(b.translated(0, 1).intersected(
@@ -179,12 +271,16 @@ void Popup::paintEvent(QPaintEvent*)
        painter.setBrush(QApplication::palette().brush(QPalette::Window));
        painter.drawRect(rect());
 
+       // Draw the arrow
+       if (!space_for_arrow())
+               return;
+
        const QPoint ArrowOffsets[] = {
                QPoint(1, 0), QPoint(0, -1), QPoint(-1, 0), QPoint(0, 1)};
 
        const QRegion a(arrow_region());
        const QRegion arrow_outline = a.subtracted(
-               a.translated(ArrowOffsets[_pos]));
+               a.translated(ArrowOffsets[pos_]));
 
        painter.setClipRegion(bubble_outline.subtracted(a).united(
                arrow_outline));
@@ -198,11 +294,6 @@ void Popup::resizeEvent(QResizeEvent*)
        setMask(popup_region());
 }
 
-void Popup::showEvent(QShowEvent*)
-{
-       reposition_widget();
-}
-
 void Popup::mouseReleaseEvent(QMouseEvent *e)
 {
        assert(e);
@@ -213,6 +304,11 @@ void Popup::mouseReleaseEvent(QMouseEvent *e)
                close();
 }
 
+void Popup::showEvent(QShowEvent*)
+{
+       reposition_widget();
+}
+
 } // namespace widgets
 } // namespace pv