File indexing completed on 2025-01-26 05:09:32

0001 /*
0002  * This file is part of the KDE wacomtablet project. For copyright
0003  * information and license terms see the AUTHORS and COPYING files
0004  * in the top-level directory of this distribution.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "tabletpagewidget.h"
0021 #include "ui_tabletpagewidget.h"
0022 
0023 #include "dbustabletinterface.h"
0024 #include "deviceprofile.h"
0025 #include "profilemanagement.h"
0026 #include "property.h"
0027 #include "screensinfo.h"
0028 #include "stringutils.h"
0029 #include "tabletareaselectiondialog.h"
0030 #include "x11wacom.h"
0031 
0032 #include <QStringList>
0033 
0034 using namespace Wacom;
0035 
0036 TabletPageWidget::TabletPageWidget(QWidget *parent)
0037     : QWidget(parent)
0038     , ui(new Ui::TabletPageWidget)
0039 {
0040     setupUi();
0041 }
0042 
0043 TabletPageWidget::~TabletPageWidget()
0044 {
0045     delete ui;
0046 }
0047 
0048 void TabletPageWidget::setTabletId(const QString &tabletId)
0049 {
0050     _tabletId = tabletId;
0051 }
0052 
0053 void TabletPageWidget::loadFromProfile(ProfileManagementInterface &profileManagement)
0054 {
0055     DeviceProfile stylusProfile = profileManagement.loadDeviceProfile(DeviceType::Stylus);
0056 
0057     setRotation(stylusProfile.getProperty(Property::Rotate));
0058     setScreenSpace(stylusProfile.getProperty(Property::ScreenSpace));
0059     setScreenMap(stylusProfile.getProperty(Property::ScreenMap));
0060     setTrackingMode(stylusProfile.getProperty(Property::Mode));
0061 }
0062 
0063 void TabletPageWidget::reloadWidget()
0064 {
0065     // get all tablet device names we need
0066     QDBusReply<QString> stylusDeviceNameReply = DBusTabletInterface::instance().getDeviceName(_tabletId, DeviceType::Stylus.key());
0067     QDBusReply<QString> touchDeviceNameReply = DBusTabletInterface::instance().getDeviceName(_tabletId, DeviceType::Touch.key());
0068 
0069     // update name and maximum tablet area for all devices
0070     _deviceNameStylus.clear();
0071     _deviceNameTouch.clear();
0072     _tabletGeometry = TabletArea();
0073     _screenMap = ScreenMap();
0074 
0075     if (stylusDeviceNameReply.isValid()) {
0076         _deviceNameStylus = stylusDeviceNameReply.value();
0077         _tabletGeometry = X11Wacom::getMaximumTabletArea(stylusDeviceNameReply.value());
0078         _screenMap = ScreenMap(_tabletGeometry);
0079     }
0080 
0081     if (touchDeviceNameReply.isValid()) {
0082         _deviceNameTouch = touchDeviceNameReply.value();
0083     }
0084 }
0085 
0086 void TabletPageWidget::saveToProfile(ProfileManagementInterface &profileManagement)
0087 {
0088     DeviceProfile padProfile = profileManagement.loadDeviceProfile(DeviceType::Pad);
0089     DeviceProfile stylusProfile = profileManagement.loadDeviceProfile(DeviceType::Stylus);
0090     DeviceProfile eraserProfile = profileManagement.loadDeviceProfile(DeviceType::Eraser);
0091     DeviceProfile touchProfile = profileManagement.loadDeviceProfile(DeviceType::Touch);
0092 
0093     stylusProfile.setProperty(Property::Rotate, getRotation());
0094     eraserProfile.setProperty(Property::Rotate, getRotation());
0095     touchProfile.setProperty(Property::Rotate, getRotation());
0096     padProfile.setProperty(Property::Rotate, QString()); // make sure it is not set on the pad - will mess up touch
0097 
0098     stylusProfile.setProperty(Property::ScreenSpace, getScreenSpaceAsString());
0099     eraserProfile.setProperty(Property::ScreenSpace, getScreenSpaceAsString());
0100     padProfile.setProperty(Property::ScreenSpace, QString()); // should not be set on the pad, causes trouble
0101     padProfile.setProperty(Property::Area, QString()); // should not be set on the pad, causes trouble
0102 
0103     stylusProfile.setProperty(Property::ScreenMap, getScreenMapAsString());
0104     eraserProfile.setProperty(Property::ScreenMap, getScreenMapAsString());
0105     padProfile.setProperty(Property::ScreenMap, QString()); // make sure it is not set on the pad
0106 
0107     stylusProfile.setProperty(Property::Mode, getTrackingMode());
0108     eraserProfile.setProperty(Property::Mode, getTrackingMode());
0109 
0110     profileManagement.saveDeviceProfile(padProfile);
0111     profileManagement.saveDeviceProfile(stylusProfile);
0112     profileManagement.saveDeviceProfile(eraserProfile);
0113 
0114     if (!_deviceNameTouch.isEmpty()) {
0115         profileManagement.saveDeviceProfile(touchProfile);
0116     }
0117 }
0118 
0119 void TabletPageWidget::onAutoRotateChanged(int state)
0120 {
0121     setAutoRotationEnabled(state == Qt::Checked);
0122     onProfileChanged();
0123 }
0124 
0125 void TabletPageWidget::onProfileChanged()
0126 {
0127     emit changed();
0128 }
0129 
0130 void TabletPageWidget::onTabletMappingClicked()
0131 {
0132     // get current rotation settings
0133     // we need to invert it as our rotation settings in this widget have a canvas viewpoint
0134     const ScreenRotation *lookupRotation = ScreenRotation::find(getRotation());
0135     ScreenRotation rotation = lookupRotation ? lookupRotation->invert() : ScreenRotation::NONE;
0136 
0137     TabletAreaSelectionDialog selectionDialog;
0138     selectionDialog.setupWidget(getScreenMap(), _deviceNameStylus, rotation);
0139     selectionDialog.select(getScreenSpace());
0140 
0141     if (selectionDialog.exec() == QDialog::Accepted) {
0142         setScreenMap(selectionDialog.getScreenMap());
0143         setScreenSpace(selectionDialog.getScreenSpace());
0144         onProfileChanged();
0145     }
0146 }
0147 
0148 void TabletPageWidget::onRotationChanged()
0149 {
0150     // determine rotation
0151     const ScreenRotation *lookupRotation = ScreenRotation::find(getRotation());
0152 
0153     // we need to invert it as our rotation settings in this widget have a canvas viewpoint
0154     // and our private member variable has a tablet viewpoint
0155     emit rotationChanged(lookupRotation ? lookupRotation->invert() : ScreenRotation::NONE);
0156 }
0157 
0158 void TabletPageWidget::onTrackingModeAbsolute(bool activated)
0159 {
0160     if (!activated) {
0161         return;
0162     }
0163 
0164     setTrackingMode(QLatin1String("absolute"));
0165     onProfileChanged();
0166 }
0167 
0168 void TabletPageWidget::onTrackingModeRelative(bool activated)
0169 {
0170     if (!activated) {
0171         return;
0172     }
0173 
0174     setTrackingMode(QLatin1String("relative"));
0175     onProfileChanged();
0176 }
0177 
0178 const QString TabletPageWidget::getRotation() const
0179 {
0180     QString rotation = ScreenRotation::NONE.key();
0181 
0182     if (isAutoRotationEnabled()) {
0183         if (isAutoRotateInversionEnabled()) {
0184             rotation = ScreenRotation::AUTO_INVERTED.key();
0185         } else {
0186             rotation = ScreenRotation::AUTO.key();
0187         }
0188     } else {
0189         int index = ui->rotatationSelectionComboBox->currentIndex();
0190         rotation = ui->rotatationSelectionComboBox->itemData(index).toString();
0191     }
0192 
0193     return rotation;
0194 }
0195 
0196 const ScreenMap &TabletPageWidget::getScreenMap() const
0197 {
0198     return _screenMap;
0199 }
0200 
0201 const QString TabletPageWidget::getScreenMapAsString() const
0202 {
0203     return getScreenMap().toString();
0204 }
0205 
0206 const ScreenSpace &TabletPageWidget::getScreenSpace() const
0207 {
0208     return _screenSpace;
0209 }
0210 
0211 const QString TabletPageWidget::getScreenSpaceAsString() const
0212 {
0213     return getScreenSpace().toString();
0214 }
0215 
0216 const QString TabletPageWidget::getTrackingMode() const
0217 {
0218     if (ui->trackAbsoluteRadioButton->isChecked()) {
0219         return QLatin1String("absolute");
0220     }
0221 
0222     return QLatin1String("relative");
0223 }
0224 
0225 bool TabletPageWidget::isAutoRotateInversionEnabled() const
0226 {
0227     return ui->rotateWithScreenInvertCheckBox->isChecked();
0228 }
0229 
0230 bool TabletPageWidget::isAutoRotationEnabled() const
0231 {
0232     return ui->rotateWithScreenCheckBox->isChecked();
0233 }
0234 
0235 void TabletPageWidget::setAutoRotateInversionEnabled(bool value)
0236 {
0237     ui->rotateWithScreenInvertCheckBox->blockSignals(true);
0238     ui->rotateWithScreenInvertCheckBox->setChecked(value);
0239     ui->rotateWithScreenInvertCheckBox->blockSignals(false);
0240 }
0241 
0242 void TabletPageWidget::setAutoRotationEnabled(bool value)
0243 {
0244     ui->rotatationSelectionComboBox->setEnabled(!value);
0245     ui->rotateWithScreenInvertCheckBox->setEnabled(value);
0246 
0247     if (value) {
0248         setRotation(ScreenRotation::NONE.key());
0249     } else {
0250         setAutoRotateInversionEnabled(false);
0251     }
0252 
0253     ui->rotateWithScreenCheckBox->blockSignals(true);
0254     ui->rotateWithScreenCheckBox->setChecked(value);
0255     ui->rotateWithScreenCheckBox->blockSignals(false);
0256 }
0257 
0258 void TabletPageWidget::setRotation(const QString &value)
0259 {
0260     const ScreenRotation *lookup = ScreenRotation::find(value);
0261     ScreenRotation rotation = lookup ? *lookup : ScreenRotation::NONE;
0262     QString rotationValue = rotation.key();
0263 
0264     if (rotation == ScreenRotation::AUTO) {
0265         setAutoRotationEnabled(true);
0266         rotationValue = ScreenRotation::NONE.key();
0267 
0268     } else if (rotation == ScreenRotation::AUTO_INVERTED) {
0269         setAutoRotationEnabled(true);
0270         setAutoRotateInversionEnabled(true);
0271         rotationValue = ScreenRotation::NONE.key();
0272     }
0273 
0274     int rotationIndex = ui->rotatationSelectionComboBox->findData(rotationValue);
0275 
0276     ui->rotatationSelectionComboBox->blockSignals(true);
0277     ui->rotatationSelectionComboBox->setCurrentIndex(rotationIndex >= 0 ? rotationIndex : 0);
0278     ui->rotatationSelectionComboBox->blockSignals(false);
0279 
0280     onRotationChanged();
0281 }
0282 
0283 void TabletPageWidget::setScreenMap(const ScreenMap &screenMap)
0284 {
0285     _screenMap = screenMap;
0286 
0287     assertValidTabletMapping();
0288 }
0289 
0290 void TabletPageWidget::setScreenMap(const QString &value)
0291 {
0292     setScreenMap(ScreenMap(value));
0293 }
0294 
0295 void TabletPageWidget::setScreenSpace(const ScreenSpace &screenSpace)
0296 {
0297     _screenSpace = screenSpace;
0298 
0299     assertValidTabletMapping();
0300 }
0301 
0302 void TabletPageWidget::setScreenSpace(const QString &value)
0303 {
0304     setScreenSpace(ScreenSpace(value));
0305 }
0306 
0307 void TabletPageWidget::setTrackingMode(const QString &value)
0308 {
0309     ui->trackAbsoluteRadioButton->blockSignals(true);
0310     ui->trackRelativeRadioButton->blockSignals(true);
0311 
0312     if (value.contains(QLatin1String("absolute"), Qt::CaseInsensitive)) {
0313         ui->trackAbsoluteRadioButton->setChecked(true);
0314         ui->trackRelativeRadioButton->setChecked(false);
0315     } else {
0316         ui->trackAbsoluteRadioButton->setChecked(false);
0317         ui->trackRelativeRadioButton->setChecked(true);
0318     }
0319 
0320     ui->trackAbsoluteRadioButton->blockSignals(false);
0321     ui->trackRelativeRadioButton->blockSignals(false);
0322 
0323     assertValidTabletMapping();
0324 }
0325 
0326 void TabletPageWidget::assertValidTabletMapping()
0327 {
0328     bool isWarningVisible = false;
0329 
0330     if (ui->trackRelativeRadioButton->isChecked()) {
0331         // Relative mode is selected. In relative mode a
0332         // device can not be mapped to a single monitor
0333         ScreenSpace screenSpace = getScreenSpace();
0334 
0335         if (screenSpace.isMonitor()) {
0336             isWarningVisible = true;
0337         }
0338     }
0339 
0340     ui->trackingWarningIcon->setVisible(isWarningVisible);
0341     ui->trackingWarningLabel->setVisible(isWarningVisible);
0342 }
0343 
0344 void TabletPageWidget::setupUi()
0345 {
0346     ui->setupUi(this);
0347 
0348     // init screen mapping warning
0349     ui->trackingWarningIcon->setPixmap(QIcon::fromTheme(QLatin1String("dialog-warning")).pixmap(QSize(16, 16)));
0350     ui->trackingWarningIcon->setVisible(false);
0351     ui->trackingWarningLabel->setVisible(false);
0352 
0353     // fill rotation combo box
0354     // xsetwacom's rotation is based on coordinate rotation, but we are asking the user for a tablet rotation.
0355     // Therefore we have to swap the values for clockwise and counterclockwise rotation.
0356     ui->rotatationSelectionComboBox->addItem(i18nc("Either no orientation or the current screen orientation is applied to the tablet.", "Default Orientation"),
0357                                              ScreenRotation::NONE.key());
0358     ui->rotatationSelectionComboBox->addItem(i18nc("The tablet will be rotated clockwise.", "Rotate Tablet Clockwise"), ScreenRotation::CCW.key());
0359     ui->rotatationSelectionComboBox->addItem(i18nc("The tablet will be rotated counterclockwise.", "Rotate Tablet Counterclockwise"), ScreenRotation::CW.key());
0360     ui->rotatationSelectionComboBox->addItem(i18nc("The tablet will be rotated up side down.", "Rotate Tablet Upside-Down"), ScreenRotation::HALF.key());
0361 }
0362 
0363 #include "moc_tabletpagewidget.cpp"