Commit 53b54ebd authored by Thomas Baumgart's avatar Thomas Baumgart
Browse files

Added general mechanism to position popup widgets

This allows to place popup widgets relative to one of the corners of a
base widget while making sure that the popup does stay on one screen.

Apply this method to calculator and date popups.

CCBUG: 434573
parent 9dd12596
Pipeline #54956 passed with stage
in 8 minutes and 5 seconds
......@@ -16,7 +16,7 @@ set(kmymoney_STAT_HEADERS
kmymoneyvalidationfeedback.h
onlinejobmessagesview.h
kmymoneydateedit.h
amountedit.h amountvalidator.h creditdebithelper.h
amountedit.h amountvalidator.h creditdebithelper.h popuppositioner.h
)
########### Shared widget library ###########
......@@ -59,6 +59,7 @@ set(kmm_widgets_sources
kmymoneyviewbase.cpp
kmymoneyaccountsviewbase.cpp
passwordtoggle.cpp
popuppositioner.cpp
)
set(nationalAccountWidget_SOURCES
......
......@@ -29,7 +29,8 @@
#include "amountvalidator.h"
#include "kmymoneycalculator.h"
#include "mymoneysecurity.h"
#include "icons/icons.h"
#include "icons.h"
#include "popuppositioner.h"
using namespace Icons;
......@@ -141,25 +142,7 @@ public:
m_calculatorFrame->show();
m_calculatorFrame->setGeometry(m_calculator->geometry());
const auto h = m_calculatorFrame->height();
const auto w = m_calculatorFrame->width();
// usually, the calculator widget is shown underneath the AmountEdit widget
// if it does not fit on the screen, we show it above this widget
auto p = q->mapToGlobal(QPoint());
if (p.y() + q->height() + h > QApplication::desktop()->availableGeometry(m_calculatorFrame).height()) {
p.setY(p.y() - h);
} else {
p.setY(p.y() + q->height());
}
// usually, it is shown left aligned. If it does not fit, we align it
// to the right edge of the AmountEdit widget
if (p.x() + w > QApplication::desktop()->availableGeometry(m_calculatorFrame).width()) {
p.setX(p.x() + q->width() - w);
}
m_calculatorFrame->move(p);
PopupPositioner pos(q, m_calculatorFrame, PopupPositioner::BottemLeft);
m_calculator->setFocus();
}
......
......@@ -34,7 +34,8 @@
// ----------------------------------------------------------------------------
// Project Includes
#include "icons/icons.h"
#include "icons.h"
#include "popuppositioner.h"
using namespace Icons;
......@@ -242,23 +243,7 @@ void KMyMoneyDateInput::toggleDatePicker()
if (d->m_dateFrame->isVisible()) {
d->m_dateFrame->hide();
} else {
QPoint tmpPoint = mapToGlobal(d->m_dateButton->geometry().bottomRight());
// usually, the datepicker widget is shown underneath the d->m_dateEdit widget
// if it does not fit on the screen, we show it above this widget
if (tmpPoint.y() + h > QApplication::desktop()->height()) {
tmpPoint.setY(tmpPoint.y() - h - d->m_dateButton->height());
}
if ((d->m_qtalignment == Qt::AlignRight && tmpPoint.x() + w <= QApplication::desktop()->width())
|| (tmpPoint.x() - w < 0)) {
d->m_dateFrame->setGeometry(tmpPoint.x() - width(), tmpPoint.y(), w, h);
} else {
tmpPoint.setX(tmpPoint.x() - w);
d->m_dateFrame->setGeometry(tmpPoint.x(), tmpPoint.y(), w, h);
}
PopupPositioner pos(d->m_dateButton, d->m_dateFrame, PopupPositioner::BottomRight);
if (d->m_date.isValid() && d->m_date != INVALID_DATE) {
d->m_datePicker->setDate(d->m_date);
} else {
......
/*
SPDX-FileCopyrightText: 2021 Thomas Baumgart <tbaumgart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "popuppositioner.h"
// ----------------------------------------------------------------------------
// QT Includes
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
#include <QWidget>
#include <QRect>
// ----------------------------------------------------------------------------
// KDE Includes
// ----------------------------------------------------------------------------
// Project Includes
PopupPositioner::PopupPositioner(QWidget* baseWidget, QWidget* popupWidget, Anchor anchor)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
const auto screen = baseWidget->screen();
#else
auto screenNr = QApplication::desktop()->screenNumber(baseWidget);
const auto screen = QApplication::desktop()->screen(screenNr);
#endif
QRect screenRect(screen->x(), screen->y(), screen->width(), screen->height());
auto p = baseWidget->mapToGlobal(QPoint());
// align the y coordinate
switch(anchor) {
case BottemLeft:
case BottomRight:
if (p.y() + baseWidget->height() + popupWidget->height() > screenRect.bottomLeft().y()) {
p.setY(p.y() - popupWidget->height());
} else {
p.setY(p.y() + baseWidget->height());
}
break;
case TopLeft:
case TopRight:
if (p.y() - popupWidget->height() < screenRect.topLeft().y()) {
p.setY(p.y() + baseWidget->height());
} else {
p.setY(p.y() - popupWidget->height());
}
break;
}
// align the x coordinate
switch(anchor) {
case BottemLeft:
case TopLeft:
// if left aligning causes the widget to leave the screen area
// then align it to the right edge of the base widget instead
if (p.x() + popupWidget->width() > screenRect.topRight().x()) {
p.setX(p.x() + baseWidget->width() - popupWidget->width());
}
break;
case BottomRight:
case TopRight:
// align to the right
p.setX(p.x() + baseWidget->width() - popupWidget->width());
// if right aligning causes the widget to leave the screen area
// then align it to the left edge of the base widget
if (p.x() < screenRect.topLeft().x()) {
p.setX(baseWidget->x());
}
break;
}
// if the popup widget leaves the screen to the left
// then align it to the left side of the screen
if (p.x() < screenRect.topLeft().x()) {
p.setX(screenRect.topLeft().x());
}
// if the popup widget leaves the screen to the right
// then align its right edge to the right side of the screen
if (p.x() + popupWidget->width() > screenRect.topRight().x()) {
p.setX(screenRect.topRight().x() - popupWidget->width());
}
// move the popup widget to its location
popupWidget->move(p);
}
/*
SPDX-FileCopyrightText: 2021 Thomas Baumgart <tbaumgart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef POPUPPOSITIONER_H
#define POPUPPOSITIONER_H
#include "kmm_widgets_export.h"
// ----------------------------------------------------------------------------
// QT Includes
class QWidget;
// ----------------------------------------------------------------------------
// KDE Includes
// ----------------------------------------------------------------------------
// Project Includes
/**
* This class represents a helper to position a @a popupWidget
* relative to a @a baseWidget while making sure that the
* popupWidget does not cross screen boundaries on a virtual
* desktop.
*
* The @
*
* @author Thomas Baumgart
*/
class KMM_WIDGETS_EXPORT PopupPositioner
{
public:
typedef enum { TopLeft, TopRight, BottemLeft, BottomRight } Anchor;
explicit PopupPositioner(QWidget* baseWidget, QWidget* popupWidget, Anchor anchor);
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment