Drop some trailing whitespace.
[pulseview.git] / pv / widgets / popup.cpp
index f89e38a6b1b84e3fdc9b923060f31688277c87f1..13282cda25e458b6b624de563f09e1fc6668a6b5 100644 (file)
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <algorithm>
+#include <cassert>
 
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QLineEdit>
 #include <QtGui>
 
-#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),
                MarginWidth + ((pos == Bottom) ? ArrowLength : 0),
                MarginWidth + ((pos == Left) ? ArrowLength : 0),
                MarginWidth + ((pos == Top) ? ArrowLength : 0));
+}
+
+bool Popup::eventFilter(QObject *obj, QEvent *event)
+{
+       QKeyEvent *keyEvent;
+
+       (void)obj;
+
+       if (event->type() == QEvent::KeyPress) {
+               keyEvent = static_cast<QKeyEvent*>(event);
+               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 int l = ArrowLength + ArrowOverlap; 
+       const QPoint p = mapFromGlobal(point_);
+       const int l = ArrowLength + ArrowOverlap;
 
-       switch (_pos)
-        {
+       switch (pos_) {
        case Right:
                poly << QPoint(p.x() + l, p.y() - l);
                break;
@@ -79,7 +151,7 @@ QPolygon Popup::arrow_polygon() const
                poly << QPoint(p.x() - l, p.y() + l);
                break;
 
-        case Left:
+       case Left:
        case Top:
                poly << QPoint(p.x() - l, p.y() - l);
                break;
@@ -87,17 +159,16 @@ QPolygon Popup::arrow_polygon() const
 
        poly << p;
 
-       switch (_pos)
-        {
+       switch (pos_) {
        case Right:
        case Bottom:
                poly << QPoint(p.x() + l, p.y() + l);
                break;
 
-        case Left:
+       case Left:
                poly << QPoint(p.x() - l, p.y() + l);
                break;
-               
+
        case Top:
                poly << QPoint(p.x() + l, p.y() - l);
                break;
@@ -114,11 +185,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 +213,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 +256,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 +266,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,21 +289,20 @@ void Popup::resizeEvent(QResizeEvent*)
        setMask(popup_region());
 }
 
-void Popup::showEvent(QShowEvent*)
+void Popup::mouseReleaseEvent(QMouseEvent *event)
 {
-       reposition_widget();
-}
-
-void Popup::mouseReleaseEvent(QMouseEvent *e)
-{
-       assert(e);
+       assert(event);
 
        // We need our own out-of-bounds click handler because QWidget counts
        // the drop-shadow region as inside the widget
-       if(!bubble_rect().contains(e->pos()))
+       if (!bubble_rect().contains(event->pos()))
                close();
 }
 
+void Popup::showEvent(QShowEvent*)
+{
+       reposition_widget();
+}
+
 } // namespace widgets
 } // namespace pv
-