diff --git a/src/kcmodule/calibrationdialog.cpp b/src/kcmodule/calibrationdialog.cpp index 70a0591..de8adb2 100644 --- a/src/kcmodule/calibrationdialog.cpp +++ b/src/kcmodule/calibrationdialog.cpp @@ -1,155 +1,165 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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, see . */ #include "calibrationdialog.h" #include "logging.h" #include "x11wacom.h" +#include "x11info.h" //KDE includes #include //Qt includes #include #include #include #include #include using namespace Wacom; const int frameGap = 10; const int boxwidth = 100; -CalibrationDialog::CalibrationDialog( const QString &toolname ) : - QDialog( ) +CalibrationDialog::CalibrationDialog(const QString &toolname, const QString &targetScreen) + : QDialog() + , m_drawCross(0) + , m_toolName(toolname) { - setWindowState( Qt::WindowFullScreen ); + auto screenList = X11Info::getScreenGeometries(); + if (screenList.count() > 1) { + if (screenList.contains(targetScreen)) { + move(screenList.value(targetScreen).topLeft()); + } else { + qCWarning(KCM) << "Calibration requested for unknown screen" << targetScreen; + } + } + + setWindowState(Qt::WindowFullScreen); - m_toolName = toolname; - m_drawCross = 0; m_shiftLeft = frameGap; m_shiftTop = frameGap; m_originaltabletArea = X11Wacom::getMaximumTabletArea(m_toolName); QLabel *showInfo = new QLabel(); showInfo->setText( i18n( "Please tap into all four corners to calibrate the tablet.\nPress escape to cancel the process." ) ); showInfo->setAlignment( Qt::AlignCenter ); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget( showInfo ); setLayout(mainLayout); } QRect CalibrationDialog::calibratedArea() { return m_newtabletArea.toRect(); } void CalibrationDialog::paintEvent( QPaintEvent *event ) { Q_UNUSED( event ); QPainter painter( this ); painter.setPen(palette().color(QPalette::WindowText)); // vertical line painter.drawLine( m_shiftLeft + boxwidth / 2, m_shiftTop, m_shiftLeft + boxwidth / 2, m_shiftTop + boxwidth ); // horizontal line painter.drawLine( m_shiftLeft, m_shiftTop + boxwidth / 2, m_shiftLeft + boxwidth, m_shiftTop + boxwidth / 2 ); // draw circle around center painter.drawEllipse( QPoint( m_shiftLeft + boxwidth / 2, m_shiftTop + boxwidth / 2 ), 10, 10 ); } void CalibrationDialog::mousePressEvent( QMouseEvent *event ) { if( event->pos().x() > m_shiftLeft && event->pos().x() < m_shiftLeft + boxwidth && event->pos().y() > m_shiftTop && event->pos().y() < m_shiftTop + boxwidth ) { m_drawCross++; switch( m_drawCross ) { case 1: m_topLeft = event->windowPos(); m_shiftLeft = frameGap; m_shiftTop = size().height() - frameGap - boxwidth; break; case 2: m_bottomLeft = event->windowPos(); m_shiftLeft = size().width() - frameGap - boxwidth; m_shiftTop = size().height() - frameGap - boxwidth; break; case 3: m_bottomRight = event->windowPos(); m_shiftLeft = size().width() - frameGap - boxwidth; m_shiftTop = frameGap; break; case 4: m_topRight = event->windowPos(); calculateNewArea(); close(); break; } update(); } } void CalibrationDialog::calculateNewArea() { qreal frameoffset = frameGeometry().height() - size().height(); qreal tabletScreenRatioWidth = m_originaltabletArea.width() / size().width(); qreal tabletScreenRatioHeight = m_originaltabletArea.height() / size().height(); const qreal clickedX = ( m_topLeft.x() + m_bottomLeft.x() ) / 2; const qreal clickedXadjusted = clickedX - frameGap - boxwidth / 2; const qreal newX = m_originaltabletArea.x() + clickedXadjusted * tabletScreenRatioWidth; const qreal clickedY = ( m_topLeft.y() + m_topRight.y() ) / 2; const qreal clickedYadjusted = clickedY - frameGap - boxwidth / 2; const qreal newY = m_originaltabletArea.y() + clickedYadjusted * tabletScreenRatioHeight; const qreal clickedXright = ( m_topRight.x() + m_bottomRight.x() ) / 2; const qreal newWidth = ( clickedXright + frameGap + boxwidth / 2 ) * tabletScreenRatioWidth; const qreal clickedYbottom = ( m_bottomRight.y() + m_bottomLeft.y() ) / 2; const qreal newHeight = ( clickedYbottom + frameGap + boxwidth / 2 + frameoffset ) * tabletScreenRatioHeight; m_newtabletArea.setX( newX ); m_newtabletArea.setY( newY ); m_newtabletArea.setRight( newWidth ); m_newtabletArea.setBottom( newHeight ); qCDebug(KCM) << "Calibration debug:" << frameGeometry() << size() << m_originaltabletArea << m_topLeft << m_bottomLeft << m_topRight << m_bottomRight; qCDebug(KCM) << "Calibration debug:" << frameoffset << tabletScreenRatioWidth << tabletScreenRatioHeight << clickedX << clickedY << clickedXright << clickedYbottom; qCDebug(KCM) << "Calibration debug:" << m_newtabletArea; } diff --git a/src/kcmodule/calibrationdialog.h b/src/kcmodule/calibrationdialog.h index 82c4144..08399a4 100644 --- a/src/kcmodule/calibrationdialog.h +++ b/src/kcmodule/calibrationdialog.h @@ -1,86 +1,87 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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, see . */ #ifndef CALIBRATIONDIALOG_H #define CALIBRATIONDIALOG_H #include namespace Wacom { /** * @brief * */ class CalibrationDialog : public QDialog { Q_OBJECT public: /** * @brief Constructs the fullscreen window for the calibration process * * @param toolname name of the tool to calibrate (stylus or touch name) + * @param targetScreen screen which is going to be used for calibration */ - explicit CalibrationDialog( const QString &toolname ); + CalibrationDialog(const QString &toolname, const QString &targetScreen); /** * @brief Returns the new tablet area * * @return Tablet area after calibration */ QRect calibratedArea(); protected: /** * @brief Draws the cross for the calibration * * The user has to hit the center of the cross for the calibration * * @param event some additional event details */ void paintEvent( QPaintEvent *event ); /** * @brief Catch mousepress events * * Only events inside the calibration cross are recognized. All other are ignored. * * @param event mouse press details */ void mousePressEvent( QMouseEvent *event ); private: /** * @brief calculates the new tablet area from all 4 calibration points */ void calculateNewArea(); int m_drawCross; /**< Which cross should be drawn? 0=topleft, 1=bottomleft, and so on */ int m_shiftLeft; /**< Where to start the cross from the left */ int m_shiftTop; /**< Where to start the cross from the top */ QString m_toolName; /**< Name of the tool to calibrate (stylus name or touch name) */ QRectF m_originaltabletArea; /**< Original tablet area before calibration */ QRectF m_newtabletArea; /**< Calibrated tablet area */ QPointF m_topLeft; /**< Top left clicked point for calibration */ QPointF m_bottomLeft; /**< Bottom left clicked point for calibration */ QPointF m_topRight; /**< Top right clicked point for calibration */ QPointF m_bottomRight; /**< Bottom right clicked point for calibration */ }; } #endif // CALIBRATIONDIALOG_H diff --git a/src/kcmodule/tabletareaselectioncontroller.cpp b/src/kcmodule/tabletareaselectioncontroller.cpp index 1f36182..695d943 100644 --- a/src/kcmodule/tabletareaselectioncontroller.cpp +++ b/src/kcmodule/tabletareaselectioncontroller.cpp @@ -1,360 +1,360 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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, see . */ #include "tabletareaselectioncontroller.h" #include "logging.h" #include "tabletareaselectionview.h" #include "calibrationdialog.h" #include "screenmap.h" #include "stringutils.h" #include "x11info.h" #include "x11wacom.h" using namespace Wacom; namespace Wacom { class TabletAreaSelectionControllerPrivate { public: TabletAreaSelectionView *view = nullptr; TabletArea tabletGeometry; // the original tablet geometry TabletArea tabletGeometryRotated; // the rotated tablet geometry if rotation is active QMap screenGeometries; // the geometries of all screens which form the desktop ScreenSpace currentScreen; QString deviceName; // the device this instance is handling ScreenMap screenMap; // the current screen mappings ScreenRotation tabletRotation = ScreenRotation::NONE; // the tablet rotation }; } TabletAreaSelectionController::TabletAreaSelectionController() : QObject(), d_ptr(new TabletAreaSelectionControllerPrivate) { // nothing to do except for initializing our private class } TabletAreaSelectionController::~TabletAreaSelectionController() { delete this->d_ptr; } const ScreenMap& TabletAreaSelectionController::getScreenMap() { Q_D(const TabletAreaSelectionController); // make sure the current mapping is included setMapping(d->currentScreen, d->view->getSelection()); // return mapping return d->screenMap; } const ScreenSpace TabletAreaSelectionController::getScreenSpace() const { Q_D(const TabletAreaSelectionController); return d->currentScreen; } void TabletAreaSelectionController::select(const ScreenSpace& screenSpace) { Q_D(TabletAreaSelectionController); if (!hasView()) { return; } setMapping(d->currentScreen, d->view->getSelection()); d->currentScreen = screenSpace; d->view->select(screenSpace.toString(), screenSpace.isDesktop(), getMapping(d->currentScreen)); } void TabletAreaSelectionController::setView(TabletAreaSelectionView* view) { Q_D(TabletAreaSelectionController); // cleanup signal/slot connections if we already have a view if (d->view) { disconnect(d->view, SIGNAL(signalCalibrateClicked()), this, SLOT(onCalibrateClicked())); disconnect(d->view, SIGNAL(signalFullTabletSelection()), this, SLOT(onFullTabletSelected())); disconnect(d->view, SIGNAL(signalScreenToggle()), this, SLOT(onScreenToggle())); disconnect(d->view, SIGNAL(signalSetScreenProportions()), this, SLOT(onSetScreenProportions())); disconnect(d->view, SIGNAL(signalTabletAreaSelection()), this, SLOT(onTabletAreaSelected())); } // save view and connect signals d->view = view; if (view) { connect(view, SIGNAL(signalCalibrateClicked()), this, SLOT(onCalibrateClicked())); connect(view, SIGNAL(signalFullTabletSelection()), this, SLOT(onFullTabletSelected())); connect(view, SIGNAL(signalScreenToggle()), this, SLOT(onScreenToggle())); connect(view, SIGNAL(signalSetScreenProportions()), this, SLOT(onSetScreenProportions())); connect(view, SIGNAL(signalTabletAreaSelection()), this, SLOT(onTabletAreaSelected())); } } void TabletAreaSelectionController::setupController(const ScreenMap& mappings, const QString& deviceName, const ScreenRotation& rotation) { Q_D(TabletAreaSelectionController); if (!hasView()) { return; } d->deviceName = deviceName; d->tabletGeometry = X11Wacom::getMaximumTabletArea(deviceName); d->screenGeometries = X11Info::getScreenGeometries(); d->screenMap = mappings; if (rotation == ScreenRotation::AUTO) { // TODO d->tabletRotation = X11Info::getScreenRotation(); // we have a tablet (not a canvas) viewpoint here, so we need to invert the screen rotation d->tabletRotation = d->tabletRotation.invert(); } else if (rotation == ScreenRotation::AUTO_INVERTED) { // TODO d->tabletRotation = X11Info::getScreenRotation(); } else { d->tabletRotation = rotation; } d->tabletGeometryRotated = d->tabletGeometry; if (d->tabletRotation == ScreenRotation::CW || d->tabletRotation == ScreenRotation::CCW) { d->tabletGeometryRotated.setWidth(d->tabletGeometry.height()); d->tabletGeometryRotated.setHeight(d->tabletGeometry.width()); } qCDebug(KCM) << "Calling setupScreens and setupTablet from setupController. ScreenGeometries: " << d->screenGeometries; d->view->setupScreens(d->screenGeometries, QSize(200,200)); d->view->setupTablet(d->tabletGeometryRotated, QSize(400,400)); // make sure we have valid data set d->view->select(d->currentScreen.toString(), d->currentScreen.isDesktop(), getMapping(d->currentScreen)); } void TabletAreaSelectionController::onCalibrateClicked() { Q_D(TabletAreaSelectionController); - CalibrationDialog calibDialog(d->deviceName); + CalibrationDialog calibDialog(d->deviceName, d->currentScreen.toString()); calibDialog.exec(); setSelection(TabletArea(calibDialog.calibratedArea())); } void TabletAreaSelectionController::onFullTabletSelected() { checkConfigurationForTrackingModeProblems(); } void TabletAreaSelectionController::onScreenToggle() { Q_D(TabletAreaSelectionController); select(d->currentScreen.next()); } void TabletAreaSelectionController::onSetScreenProportions() { Q_D(TabletAreaSelectionController); QRect tabletGeometry = d->tabletGeometryRotated; QRect screenSelection = getScreenGeometry(d->currentScreen.toString()); if (screenSelection.isEmpty()) { return; } // calculate new height and width of the selection qreal screenAreaSelectionRatio = (float)screenSelection.width() / screenSelection.height(); qreal newWidth, newHeight; if (screenSelection.width() > screenSelection.height()) { newWidth = tabletGeometry.width(); newHeight = newWidth / screenAreaSelectionRatio; if (newHeight > tabletGeometry.height()) { newHeight = tabletGeometry.height(); newWidth = newHeight * screenAreaSelectionRatio; } } else { newHeight = tabletGeometry.height(); newWidth = newHeight * screenAreaSelectionRatio; if (newWidth > tabletGeometry.width()) { newWidth = tabletGeometry.width(); newHeight = newWidth / screenAreaSelectionRatio; } } // calculate x and y to center the selection int newX = tabletGeometry.x() + (int)((tabletGeometry.width() - newWidth) / 2.); int newY = tabletGeometry.y() + (int)((tabletGeometry.height() - newHeight) / 2.); setSelection(TabletArea(QRect(newX, newY, qRound(newWidth), qRound(newHeight)))); } void TabletAreaSelectionController::onTabletAreaSelected() { checkConfigurationForTrackingModeProblems(); } bool TabletAreaSelectionController::hasView() const { Q_D(const TabletAreaSelectionController); return (d->view != nullptr); } void TabletAreaSelectionController::checkConfigurationForTrackingModeProblems() { Q_D(TabletAreaSelectionController); // a device can not be mapped to a single screen in relative mode if (d->currentScreen.isMonitor()) { d->view->setTrackingModeWarning(true); } else { d->view->setTrackingModeWarning(false); } } const TabletArea TabletAreaSelectionController::convertAreaFromRotation(const TabletArea &tablet, const TabletArea &area, const ScreenRotation &rotation) const { TabletArea result = area; if (rotation == ScreenRotation::CW) { result.setX(area.y()); result.setY(tablet.height() - area.x() - area.width()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::CCW) { result.setX(tablet.width() - area.y() - area.height()); result.setY(area.x()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::HALF) { result.setX(tablet.width() - area.width() - area.x()); result.setY(tablet.height() - area.height() - area.y()); result.setWidth(area.width()); result.setHeight(area.height()); } return result; } const TabletArea TabletAreaSelectionController::convertAreaToRotation(const TabletArea &tablet, const TabletArea &area, const ScreenRotation &rotation) const { TabletArea result = area; if (rotation == ScreenRotation::CW) { result.setX(tablet.height() - area.height() - area.y()); result.setY(area.x()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::CCW) { result.setX(area.y()); result.setY(tablet.width() - area.width() - area.x()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::HALF) { result.setX(tablet.width() - area.width() - area.x()); result.setY(tablet.height() - area.height() - area.y()); result.setWidth(area.width()); result.setHeight(area.height()); } return result; } const QRect TabletAreaSelectionController::getScreenGeometry(QString output) const { Q_D(const TabletAreaSelectionController); return d->screenGeometries.value(output, X11Info::getDisplayGeometry()); } const TabletArea TabletAreaSelectionController::getMapping(ScreenSpace screenSpace) const { Q_D(const TabletAreaSelectionController); return convertAreaToRotation(d->tabletGeometry, d->screenMap.getMapping(screenSpace), d->tabletRotation); } void TabletAreaSelectionController::setMapping(ScreenSpace screenSpace, const TabletArea &mapping) { Q_D(TabletAreaSelectionController); TabletArea area = convertAreaFromRotation(d->tabletGeometry, mapping, d->tabletRotation); d->screenMap.setMapping(screenSpace, area); } void TabletAreaSelectionController::setSelection(const TabletArea &selection) { Q_D(TabletAreaSelectionController); if (!hasView()) { return; } if (selection.isEmpty() || selection == d->tabletGeometryRotated) { d->view->selectFullTablet(); } else { d->view->selectPartOfTablet(selection); } }