diff --git a/src/kcmodule/areaselectionwidget.cpp b/src/kcmodule/areaselectionwidget.cpp index 63de38b..806ef4f 100644 --- a/src/kcmodule/areaselectionwidget.cpp +++ b/src/kcmodule/areaselectionwidget.cpp @@ -1,957 +1,960 @@ /* * 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 "areaselectionwidget.h" #include #include #include #include #include #include #include #include #include using namespace Wacom; namespace Wacom { class AreaSelectionWidgetPrivate { public: AreaSelectionWidgetPrivate() { // set some reasonable default values dragMode = AreaSelectionWidget::DragMode::DragNone; widgetTargetSize = QSize(400,400); outOfBoundsMargin = 0.; outOfBoundsVirtualAreaMargin = 0.; outOfBoundsDisplayAreaMargin = 0.; scaleFactor = .1; // prevent division by zero. drawAreaCaption = true; drawSelectionCaption = true; fontCaptions = QFont(QLatin1String("sans"), 10); // TODO: set colors based on UI theme colorDisplayAreaBrush = QColor(Qt::lightGray); colorDisplayAreaPen = QColor(Qt::black); colorDisplayAreaText = QColor(Qt::black); colorSelectedAreaBrush = QColor("#9EAEBF"); colorSelectedAreaPen = QColor("#555E67"); colorSelectedAreaText = QColor(colorSelectedAreaPen); colorDragHandles = QColor(colorSelectedAreaPen); } static const qreal DISPLAY_AREA_EXTRA_MARGIN; //!< An extra margin around the display area which is not taken into account for out of bounds calculations. static const qreal DRAG_HANDLE_SIZE; //!< The size of the drag handles. bool drawAreaCaption; //!< Determines if the caption of the display areas should be drawn. bool drawSelectionCaption; //!< Determines if the caption of the selected area should be drawn. QColor colorDisplayAreaPen; //!< The outline color of the display areas. QColor colorDisplayAreaBrush; //!< The fill colors of the display areas. QColor colorDisplayAreaText; //!< The text color of the display areas. QColor colorDragHandles; //!< The color used for the drag handles. QColor colorSelectedAreaPen; //!< The outline color of the selected area. QColor colorSelectedAreaBrush; //!< The fill color of the selected area. QColor colorSelectedAreaText; //!< The text color of the selected area. QFont fontCaptions; //!< The font used for all captions. AreaSelectionWidget::DragMode dragMode; //!< The current dragging mode if any. QPoint dragPoint; //!< The last mouse position while dragging the selected area. QSize widgetTargetSize; //!< The size of the widget we want, if possible. qreal outOfBoundsMargin; //!< The out of bounds margin as set by the user. qreal outOfBoundsVirtualAreaMargin; //!< The number of real pixels (or a percentage) the user may drag the selected area outside of the virtual area. qreal outOfBoundsDisplayAreaMargin; //!< The number of widget pixels which are calculated from the oob virtual area margin. qreal scaleFactor; //!< The scale factor which scales the virtual area's size to the widget's display area size. QMap areaRectsList; //!< The list of area rectangles which form the virtual area in real size. QStringList areaCaptionsList; //!< The list of captions for each area. QRect rectVirtualArea; //!< The rectangle which holds the virtual area in real size. QRectF rectDisplayArea; //!< The rectangle which holds the scaled virtual area displayed to the user. QList rectDisplayAreas; //!< The list of scaled sub-areas which make up the display area. QRectF rectSelectedArea; //!< The rectangle which holds the size and position of the selected display area. QRect rectDragHandleTop; //!< The rectangle which holds the size and position of the top drag handle. QRect rectDragHandleRight; //!< The rectangle which holds the size and position of the right drag handle. QRect rectDragHandleBottom; //!< The rectangle which holds the size and position of the bottom drag handle. QRect rectDragHandleLeft; //!< The rectangle which holds the size and position of the top drag handle. qreal proportions = 1; bool proportionsLocked = false; }; // PRIVATE CLASS const qreal AreaSelectionWidgetPrivate::DISPLAY_AREA_EXTRA_MARGIN = 5.; const qreal AreaSelectionWidgetPrivate::DRAG_HANDLE_SIZE = 6.; } // NAMESPACE AreaSelectionWidget::AreaSelectionWidget(QWidget* parent) : QWidget(parent), d_ptr(new AreaSelectionWidgetPrivate) { } AreaSelectionWidget::~AreaSelectionWidget() { delete this->d_ptr; } void AreaSelectionWidget::clearSelection() { Q_D(const AreaSelectionWidget); - setSelection(d->rectVirtualArea); + setSelection(d->rectVirtualArea, true); } const QRect AreaSelectionWidget::getSelection() const { Q_D(const AreaSelectionWidget); return calculateUnscaledArea(d->rectSelectedArea, d->scaleFactor, getTotalDisplayAreaMargin()); } const QString AreaSelectionWidget::getSelectionAsString() const { QRect area = getSelection(); return QString::fromLatin1("%1 %2 %3 %4").arg(area.x()).arg(area.y()).arg(area.width()).arg(area.height()); } const QRect& AreaSelectionWidget::getVirtualArea() const { Q_D(const AreaSelectionWidget); return d->rectVirtualArea; } void AreaSelectionWidget::setArea(const QRect& area, const QString& caption) { QMap areaList; QStringList captionList; areaList[caption] = area; captionList.append(caption); setAreas(areaList, captionList); } void AreaSelectionWidget::setAreas(const QMap &areas, const QStringList &areaCaptions) { Q_D (AreaSelectionWidget); d->areaRectsList = areas; d->areaCaptionsList = areaCaptions; setupWidget(); } void AreaSelectionWidget::setDrawAreaCaptions(bool value) { Q_D(AreaSelectionWidget); d->drawAreaCaption = value; } void AreaSelectionWidget::setDrawSelectionCaption(bool value) { Q_D(AreaSelectionWidget); d->drawSelectionCaption = value; } void AreaSelectionWidget::setFont(const QFont& font) { Q_D(AreaSelectionWidget); d->fontCaptions = font; } void AreaSelectionWidget::setOutOfBoundsMargin(qreal margin) { Q_D(AreaSelectionWidget); if (margin < 0.) { return; } d->outOfBoundsMargin = margin; setupWidget(); } -void AreaSelectionWidget::setSelection(const QRect& selection) +void AreaSelectionWidget::setSelection(const QRect& selection, bool emitUpdate) { Q_D(AreaSelectionWidget); // we can not select anything if we do not have areas to select from if (d->areaRectsList.isEmpty()) { return; } // if every value is -1 then the user wants to set the selection to the maximum QRect newSelection = selection; if (!selection.isValid() || (selection.x() == -1 && selection.y() == -1 && selection.width() == -1 && selection.height() == -1)) { newSelection = d->rectVirtualArea; } // update selection and repaint widget d->rectSelectedArea = calculateScaledArea(newSelection, d->scaleFactor, getTotalDisplayAreaMargin()); if (d->proportionsLocked) { lockProportions(true); } updateSelectedAreaSize(); updateDragHandles(); QWidget::update(); + + if (emitUpdate) { + emit selectionChanged(); + } } void AreaSelectionWidget::setSelection(QString output) { Q_D(const AreaSelectionWidget); const auto areaRect = d->areaRectsList.find(output); if (areaRect == d->areaRectsList.constEnd()) { return; } - setSelection(*areaRect); + setSelection(*areaRect, true); } void AreaSelectionWidget::setWidgetTargetSize(const QSize& size) { Q_D(AreaSelectionWidget); if (size.height() <= 0 || size.width() <= 0) { return; } d->widgetTargetSize = size; setupWidget(); } void AreaSelectionWidget::lockProportions(bool enable) { Q_D(AreaSelectionWidget); d->proportionsLocked = enable; if (enable && d->rectSelectedArea.height() > 0) { d->proportions = d->rectSelectedArea.width() / d->rectSelectedArea.height(); } } void AreaSelectionWidget::mouseMoveEvent(QMouseEvent* event) { Q_D(AreaSelectionWidget); // do nothing if we do not have areas set if (d->areaRectsList.isEmpty()) { return; } updateMouseCursor(event->pos()); updateSelectedAreaOnDrag(event->pos()); updateDragHandles(); QWidget::update(); } void AreaSelectionWidget::mousePressEvent(QMouseEvent* event) { Q_D (AreaSelectionWidget); // do nothing if we do not have areas set or if the user is already dragging if (d->areaRectsList.isEmpty() || isUserDragging()) { return; } // determine what the user wants to drag - a handle or the whole selected area const QPoint mousePosition(event->pos()); if (d->rectDragHandleTop.contains(mousePosition)){ d->dragMode = AreaSelectionWidget::DragMode::DragTopHandle; } else if (d->rectDragHandleRight.contains(mousePosition)) { d->dragMode = AreaSelectionWidget::DragMode::DragRightHandle; } else if (d->rectDragHandleBottom.contains(mousePosition)) { d->dragMode = AreaSelectionWidget::DragMode::DragBottomHandle; } else if (d->rectDragHandleLeft.contains(mousePosition)) { d->dragMode = AreaSelectionWidget::DragMode::DragLeftHandle; } else if (d->rectSelectedArea.contains(mousePosition)) { d->dragMode = AreaSelectionWidget::DragMode::DragSelectedArea; d->dragPoint = mousePosition; QWidget::setCursor(Qt::SizeAllCursor); } else { // the user did not click anything that is dragable d->dragMode = AreaSelectionWidget::DragMode::DragNone; } } void AreaSelectionWidget::mouseReleaseEvent(QMouseEvent* event) { Q_D(AreaSelectionWidget); Q_UNUSED(event); // do nothing if we do not have areas set if (d->areaRectsList.isEmpty()) { return; } // if the user was dragging something, he is no longer now if (isUserDragging()) { d->dragMode = AreaSelectionWidget::DragMode::DragNone; QWidget::setCursor(Qt::ArrowCursor); emit selectionChanged(); } } void AreaSelectionWidget::paintEvent(QPaintEvent* event) { Q_D(AreaSelectionWidget); Q_UNUSED(event); // draw nothing if we do not have areas set if (d->areaRectsList.isEmpty()) { QWidget::paintEvent(event); return; } QPainter painter( this ); painter.setRenderHint( QPainter::Antialiasing ); paintDisplayAreas(painter, false); paintSelectedArea(painter, false); paintDisplayAreas(painter, true); if (QWidget::isEnabled()) { paintDragHandles(painter); } if (d->drawAreaCaption) { paintDisplayAreaCaptions(painter); } if (d->drawSelectionCaption) { paintSelectedAreaCaption(painter); } } const QRectF AreaSelectionWidget::calculateDisplayArea(const QRect& virtualArea, qreal scaleFactor, qreal totalDisplayAreaMargin) const { QRectF displayArea; displayArea.setX(totalDisplayAreaMargin); displayArea.setY(totalDisplayAreaMargin); displayArea.setWidth(virtualArea.width() * scaleFactor); displayArea.setHeight(virtualArea.height() * scaleFactor); return displayArea; } const QList< QRectF > AreaSelectionWidget::calculateDisplayAreas(const QMap areas, qreal scaleFactor, qreal totalDisplayAreaMargin) const { QList displayAreas; QRectF displayArea; foreach (QRect area, areas.values()) { displayArea = calculateScaledArea(area, scaleFactor, totalDisplayAreaMargin); displayAreas.append(displayArea); } return displayAreas; } qreal AreaSelectionWidget::calculateOutOfBoundsVirtualAreaMargin(const QRect& virtualArea, qreal outOfBoundsMargin) const { if (!virtualArea.isValid() || outOfBoundsMargin < 0.) { return 0.; } qreal margin = outOfBoundsMargin; if (outOfBoundsMargin <= 1.) { // out of bounds margin is a percentage - use the longer side of the virtual area as baseline if (virtualArea.width() > virtualArea.height()) { margin = outOfBoundsMargin * virtualArea.width(); } else { margin = outOfBoundsMargin * virtualArea.height(); } } return margin; } qreal AreaSelectionWidget::calculateScaleFactor(const QSize& targetSize, const QRect& virtualArea, qreal virtualAreaOutOfBoundsMargin, qreal displayAreaExtraMargin) const { qreal scaleFactor = 0.1; // default is 10% to prevent a division by zero if (!virtualArea.isValid() || virtualArea.width() <= 0 || virtualArea.height() <= 0) { return scaleFactor; } if (virtualArea.width() > virtualArea.height()) { scaleFactor = (targetSize.width() - 2. * displayAreaExtraMargin) / (virtualArea.width() + 2. * virtualAreaOutOfBoundsMargin); } else { scaleFactor = (targetSize.height() - 2. * displayAreaExtraMargin) / (virtualArea.height() + 2. * virtualAreaOutOfBoundsMargin); } return scaleFactor; } const QRectF AreaSelectionWidget::calculateScaledArea(const QRect& area, qreal scaleFactor, qreal totalDisplayAreaMargin) const { QRectF scaledArea; scaledArea.setX(area.x() * scaleFactor + totalDisplayAreaMargin); scaledArea.setY(area.y() * scaleFactor + totalDisplayAreaMargin); scaledArea.setWidth(area.width() * scaleFactor); scaledArea.setHeight(area.height() * scaleFactor); return scaledArea; } const QRect AreaSelectionWidget::calculateUnscaledArea(const QRectF& area, qreal scaleFactor, qreal totalDisplayAreaMargin) const { QRect unscaledArea; unscaledArea.setX(qRound((area.x() - totalDisplayAreaMargin) / scaleFactor)); unscaledArea.setY(qRound((area.y() - totalDisplayAreaMargin) / scaleFactor)); unscaledArea.setWidth(qRound(area.width() / scaleFactor)); unscaledArea.setHeight(qRound(area.height() / scaleFactor)); return unscaledArea; } const QRect AreaSelectionWidget::calculateVirtualArea(const QMap &areas) const { QRect virtualArea; for (const auto &area : areas) { virtualArea = virtualArea.united(area); } return virtualArea; } qreal AreaSelectionWidget::getTotalDisplayAreaMargin() const { Q_D(const AreaSelectionWidget); return (d->outOfBoundsDisplayAreaMargin + d->DISPLAY_AREA_EXTRA_MARGIN); } bool AreaSelectionWidget::isUserDragging() const { Q_D(const AreaSelectionWidget); return (d->dragMode != AreaSelectionWidget::DragMode::DragNone); } void AreaSelectionWidget::paintDisplayAreaCaptions(QPainter& painter) { Q_D(AreaSelectionWidget); QRectF area; QString caption; qreal captionX; qreal captionY; QFontMetrics fontMetrics(d->fontCaptions); painter.setPen( d->colorDisplayAreaText ); painter.setBrush( d->colorDisplayAreaText ); painter.setFont(d->fontCaptions); for (int i = 0 ; i < d->rectDisplayAreas.size() ; ++i) { area = d->rectDisplayAreas.at(i); caption = (d->areaCaptionsList.size() > i) ? d->areaCaptionsList.at(i) : QString(); if (!caption.isEmpty() && area.isValid()) { captionX = area.x() + (float)area.width() / 2 - (float)fontMetrics.width(caption) / 2; captionY = area.y() + (float)area.height() / 2 + (float)fontMetrics.height() / 2; painter.drawText(captionX, captionY, caption); } } } void AreaSelectionWidget::paintDisplayAreas(QPainter& painter, bool outlineOnly) { Q_D(AreaSelectionWidget); // paint the whole display area painter.setPen( d->colorDisplayAreaPen ); painter.setBrush( outlineOnly ? Qt::transparent : d->colorDisplayAreaBrush ); if (d->rectDisplayAreas.size() > 1) { painter.drawRect( d->rectDisplayArea ); } // paint the display sub areas and captions QRectF area; for (int i = 0 ; i < d->rectDisplayAreas.size() ; ++i) { area = d->rectDisplayAreas.at(i); if (area.isValid()) { painter.drawRect(area); } } } void AreaSelectionWidget::paintDragHandles(QPainter& painter) { Q_D(AreaSelectionWidget); QColor color("#326583"); painter.setPen( d->colorSelectedAreaPen ); painter.setBrush( d->colorSelectedAreaPen ); painter.drawRect(d->rectDragHandleTop); painter.drawRect(d->rectDragHandleRight); painter.drawRect(d->rectDragHandleBottom); painter.drawRect(d->rectDragHandleLeft); } void AreaSelectionWidget::paintSelectedArea(QPainter& painter, bool outlineOnly) { Q_D(AreaSelectionWidget); painter.setPen( d->colorSelectedAreaPen ); painter.setBrush(outlineOnly ? Qt::transparent : d->colorSelectedAreaBrush); painter.drawRect( d->rectSelectedArea ); } void AreaSelectionWidget::paintSelectedAreaCaption(QPainter& painter) { Q_D(AreaSelectionWidget); QFontMetrics fontMetrics(d->fontCaptions); painter.setPen(d->colorSelectedAreaText); painter.setBrush(d->colorSelectedAreaText); painter.setFont(d->fontCaptions); QRect selectedArea = getSelection(); QString text = QString::fromLatin1("%1x%2+%3+%4") .arg(selectedArea.width()) .arg(selectedArea.height()) .arg(selectedArea.x()) .arg(selectedArea.y()); qreal textX = d->rectDisplayArea.x() + (qreal)d->rectDisplayArea.width() / 2 - (qreal)fontMetrics.width(text) / 2; qreal textY; if (paintBelow) { // Draw text below the display area textY = d->rectDisplayArea.y() + d->rectDisplayArea.height() + ((qreal)fontMetrics.height()); } else { // Draw in the middle of the display area textY = d->rectDisplayArea.y() + d->rectDisplayArea.height() / 2 + (qreal)fontMetrics.height() / 2; // If we are also showing area captions, then the vertical center will // already be occupied. We move our text a bit further down then. if (d->drawAreaCaption) { textY = textY + fontMetrics.height(); } } painter.drawText(qRound(textX), qRound(textY), text); } void AreaSelectionWidget::setupWidget() { Q_D(AreaSelectionWidget); // do nothing if we do not have areas if (d->areaRectsList.isEmpty()) { return; } // calculate transformation data d->rectVirtualArea = calculateVirtualArea(d->areaRectsList); d->outOfBoundsVirtualAreaMargin = calculateOutOfBoundsVirtualAreaMargin(d->rectVirtualArea, d->outOfBoundsMargin); d->scaleFactor = calculateScaleFactor(d->widgetTargetSize, d->rectVirtualArea, d->outOfBoundsVirtualAreaMargin, d->DISPLAY_AREA_EXTRA_MARGIN); d->outOfBoundsDisplayAreaMargin = d->outOfBoundsVirtualAreaMargin * d->scaleFactor; d->rectDisplayArea = calculateDisplayArea(d->rectVirtualArea, d->scaleFactor, getTotalDisplayAreaMargin()); d->rectDisplayAreas = calculateDisplayAreas(d->areaRectsList, d->scaleFactor, getTotalDisplayAreaMargin()); // setup widget QWidget::setMouseTracking( true ); qreal widgetWidth = d->rectDisplayArea.width() + 2. * getTotalDisplayAreaMargin(); qreal widgetHeight = d->rectDisplayArea.height() + 2. * getTotalDisplayAreaMargin(); QWidget::setMinimumSize(widgetWidth, widgetHeight); QWidget::setMaximumSize(widgetWidth, widgetHeight); // set selected area to the full display area d->rectSelectedArea = d->rectDisplayArea; // recalculate drag handles positions updateDragHandles(); } void AreaSelectionWidget::updateDragHandles() { Q_D (AreaSelectionWidget); // the size of the drag handles static const qreal handleSize = d->DRAG_HANDLE_SIZE; static const qreal handleSizeHalf = handleSize / 2.; // some convenience vars so we have to type less const qreal areaX = d->rectSelectedArea.x(); const qreal areaY = d->rectSelectedArea.y(); const qreal areaW = d->rectSelectedArea.width(); const qreal areaWHalf = areaW / 2.; const qreal areaH = d->rectSelectedArea.height(); const qreal areaHHalf = areaH / 2.; d->rectDragHandleTop.setX(areaX + areaWHalf - handleSizeHalf); d->rectDragHandleTop.setY(areaY - handleSizeHalf); d->rectDragHandleTop.setWidth(handleSize); d->rectDragHandleTop.setHeight(handleSize); d->rectDragHandleRight.setX(areaX + areaW - handleSizeHalf); d->rectDragHandleRight.setY(areaY + areaHHalf - handleSizeHalf); d->rectDragHandleRight.setWidth(handleSize); d->rectDragHandleRight.setHeight(handleSize); d->rectDragHandleBottom.setX(areaX + areaWHalf - handleSizeHalf); d->rectDragHandleBottom.setY(areaY + areaH - handleSizeHalf); d->rectDragHandleBottom.setWidth(handleSize); d->rectDragHandleBottom.setHeight(handleSize); d->rectDragHandleLeft.setX(areaX - handleSizeHalf); d->rectDragHandleLeft.setY(areaY + areaHHalf - handleSizeHalf); d->rectDragHandleLeft.setWidth(handleSize); d->rectDragHandleLeft.setHeight(handleSize); } void AreaSelectionWidget::updateMouseCursor(const QPoint& mousePosition) { Q_D(AreaSelectionWidget); // only update the cursor if the user is not dragging a handle. if (isUserDragging()) { return; } if (d->rectDragHandleLeft.contains(mousePosition) || d->rectDragHandleRight.contains(mousePosition)) { QWidget::setCursor( Qt::SizeHorCursor ); } else if (d->rectDragHandleTop.contains(mousePosition) || d->rectDragHandleBottom.contains(mousePosition)) { QWidget::setCursor( Qt::SizeVerCursor ); } else { QWidget::setCursor( Qt::ArrowCursor ); } } void AreaSelectionWidget::updateSelectedAreaOnDrag(const QPoint& mousePosition) { Q_D (AreaSelectionWidget); switch (d->dragMode) { - case AreaSelectionWidget::DragMode::DragTopHandle: - updateSelectedAreaOnDragTop(mousePosition); - break; + case DragMode::DragNone: + break; - case AreaSelectionWidget::DragMode::DragRightHandle: - updateSelectedAreaOnDragRight(mousePosition); - break; + case AreaSelectionWidget::DragMode::DragTopHandle: + updateSelectedAreaOnDragTop(mousePosition); + break; - case AreaSelectionWidget::DragMode::DragBottomHandle: - updateSelectedAreaOnDragBottom(mousePosition); - break; + case AreaSelectionWidget::DragMode::DragRightHandle: + updateSelectedAreaOnDragRight(mousePosition); + break; - case AreaSelectionWidget::DragMode::DragLeftHandle: - updateSelectedAreaOnDragLeft(mousePosition); - break; + case AreaSelectionWidget::DragMode::DragBottomHandle: + updateSelectedAreaOnDragBottom(mousePosition); + break; - case AreaSelectionWidget::DragMode::DragSelectedArea: - updateSelectedAreaOnDragArea(mousePosition); - break; + case AreaSelectionWidget::DragMode::DragLeftHandle: + updateSelectedAreaOnDragLeft(mousePosition); + break; - default: - // prevent compiler warning - break; + case AreaSelectionWidget::DragMode::DragSelectedArea: + updateSelectedAreaOnDragArea(mousePosition); + break; } } void AreaSelectionWidget::updateSelectedAreaOnDragArea(const QPoint& mousePosition) { Q_D (AreaSelectionWidget); const qreal dragXOffset = mousePosition.x() - d->dragPoint.x(); const qreal dragYOffset = mousePosition.y() - d->dragPoint.y(); const qreal leftBound = d->rectDisplayArea.x() - d->outOfBoundsDisplayAreaMargin; const qreal rightBound = d->rectDisplayArea.x() + d->rectDisplayArea.width() + d->outOfBoundsDisplayAreaMargin - d->rectSelectedArea.width(); const qreal topBound = d->rectDisplayArea.y() - d->outOfBoundsDisplayAreaMargin; const qreal bottomBound = d->rectDisplayArea.y() + d->rectDisplayArea.height() + d->outOfBoundsDisplayAreaMargin - d->rectSelectedArea.height(); const qreal oldW = d->rectSelectedArea.width(); const qreal oldH = d->rectSelectedArea.height(); const qreal oldX = d->rectSelectedArea.x(); const qreal oldY = d->rectSelectedArea.y(); qreal newX = oldX + dragXOffset; qreal newY = oldY + dragYOffset; // use old values if the new ones are out of bounds if (newX < leftBound || rightBound < newX) { newX = oldX; } if (newY < topBound || bottomBound < newY) { newY = oldY; } // update selected area d->rectSelectedArea.setX(newX); d->rectSelectedArea.setY(newY); d->rectSelectedArea.setWidth(oldW); d->rectSelectedArea.setHeight(oldH); // update last drag point d->dragPoint = mousePosition; updateSelectedAreaSize(false); } void AreaSelectionWidget::updateSelectedAreaOnDragBottom(const QPoint& mousePosition) { Q_D (AreaSelectionWidget); // the drag handle size in the bounds calculations ensure that the // box does not get too small to reach the drag handles with the mouse const qreal topBound = d->rectSelectedArea.y() + d->DRAG_HANDLE_SIZE; const qreal bottomBound = d->rectDisplayArea.y() + d->rectDisplayArea.height() + d->outOfBoundsDisplayAreaMargin; const qreal mouseY = mousePosition.y(); qreal newHeight = 0.; if (mouseY < topBound) { newHeight = topBound - d->rectSelectedArea.y(); } else if (mouseY > bottomBound) { newHeight = bottomBound - d->rectSelectedArea.y(); } else { newHeight = mouseY - d->rectSelectedArea.y(); } if (d->proportionsLocked) { const auto newWidth = newHeight * d->proportions; if (newWidth < topBound || newWidth > bottomBound) return; d->rectSelectedArea.setWidth(newWidth); } d->rectSelectedArea.setHeight(newHeight); updateSelectedAreaSize(true); } void AreaSelectionWidget::updateSelectedAreaOnDragLeft(const QPoint& mousePosition) { Q_D (AreaSelectionWidget); // the drag handle size in the bounds calculations ensure that the // box does not get too small to reach the drag handles with the mouse const qreal leftBound = d->rectDisplayArea.x() - d->outOfBoundsDisplayAreaMargin; const qreal rightBound = d->rectSelectedArea.x() + d->rectSelectedArea.width() - d->DRAG_HANDLE_SIZE; const qreal mouseX = mousePosition.x(); qreal newX = 0.; if (mouseX < leftBound) { newX = leftBound; } else if (mouseX > rightBound) { newX = rightBound; } else { newX = mouseX; } if (d->proportionsLocked) { const auto newY = d->rectSelectedArea.y() + (newX - d->rectSelectedArea.x()) / d->proportions; if (newY < leftBound || newY > rightBound) return; d->rectSelectedArea.setY(newY); } d->rectSelectedArea.setX(newX); updateSelectedAreaSize(false); } void AreaSelectionWidget::updateSelectedAreaOnDragRight(const QPoint& mousePosition) { Q_D (AreaSelectionWidget); // the drag handle size in the bounds calculations ensure that the // box does not get too small to reach the drag handles with the mouse const qreal leftBound = d->rectSelectedArea.x() + d->DRAG_HANDLE_SIZE; const qreal rightBound = d->rectDisplayArea.x() + d->rectDisplayArea.width() + d->outOfBoundsDisplayAreaMargin; const qreal mouseX = mousePosition.x(); qreal newWidth = 0.; if (mouseX < leftBound) { newWidth = leftBound - d->rectSelectedArea.x(); } else if (mouseX > rightBound) { newWidth = rightBound - d->rectSelectedArea.x(); } else { newWidth = mouseX - d->rectSelectedArea.x(); } if (d->proportionsLocked) { const auto newHeight = newWidth / d->proportions; if (newHeight < leftBound || newHeight > rightBound) return; d->rectSelectedArea.setHeight(newWidth / d->proportions); } d->rectSelectedArea.setWidth(newWidth); updateSelectedAreaSize(true); } void AreaSelectionWidget::updateSelectedAreaOnDragTop(const QPoint& mousePosition) { Q_D (AreaSelectionWidget); // the drag handle size in the bounds calculations ensure that the // box does not get too small to reach the drag handles with the mouse const qreal topBound = d->rectDisplayArea.y() - d->outOfBoundsDisplayAreaMargin; const qreal bottomBound = d->rectSelectedArea.y() + d->rectSelectedArea.height() - d->DRAG_HANDLE_SIZE; const qreal mouseY = mousePosition.y(); qreal newY = 0.; if (mouseY < topBound) { newY = topBound; } else if (mouseY > bottomBound) { newY = bottomBound; } else { newY = mouseY; } if (d->proportionsLocked) { const auto newX = d->rectSelectedArea.x() + (newY - d->rectSelectedArea.y()) * d->proportions; if (newX < topBound || newX > bottomBound) return; d->rectSelectedArea.setX(newX); } d->rectSelectedArea.setY(newY); updateSelectedAreaSize(false); } void AreaSelectionWidget::updateSelectedAreaSize(bool fixPositionInsteadOfSize) { Q_D(AreaSelectionWidget); // the selected area might be too large but // we expect it to be within valid bounds qreal selectedWidth = d->rectSelectedArea.width(); qreal selectedHeight = d->rectSelectedArea.height(); qreal displayWidth = d->rectDisplayArea.width(); qreal displayHeight = d->rectDisplayArea.height(); if (selectedWidth > displayWidth) { if (fixPositionInsteadOfSize) { qreal newX = d->rectSelectedArea.x() + selectedWidth - displayWidth; d->rectSelectedArea.setX(newX); } else { d->rectSelectedArea.setWidth(displayWidth); } } if (selectedHeight > displayHeight) { if (fixPositionInsteadOfSize) { qreal newY = d->rectSelectedArea.y() + selectedHeight - displayHeight; d->rectSelectedArea.setY(newY); } else { d->rectSelectedArea.setHeight(displayHeight); } } } diff --git a/src/kcmodule/areaselectionwidget.h b/src/kcmodule/areaselectionwidget.h index 7bd93a1..8743710 100644 --- a/src/kcmodule/areaselectionwidget.h +++ b/src/kcmodule/areaselectionwidget.h @@ -1,430 +1,430 @@ /* * 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 AREASELECTIONWIDGET_H #define AREASELECTIONWIDGET_H #include #include #include #include #include class QBrush; class QPainter; namespace Wacom { class AreaSelectionWidgetPrivate; class AreaSelectionWidget : public QWidget { Q_OBJECT public: bool paintBelow{false}; explicit AreaSelectionWidget(QWidget* parent = 0); virtual ~AreaSelectionWidget(); /** * Resets the selection back to the full size. */ void clearSelection(); /** * Gets the currently selected area. * * @return The currently selected area. */ const QRect getSelection() const; /** * Returns the current selection as string. * Format is: "x y width height" * * @return The current selection as string. */ const QString getSelectionAsString() const; /** * @return The virtual area rectangle which is the union of all areas currently set. */ const QRect& getVirtualArea() const; /** * Sets the area which should be scaled and displayed to the user. * * @param area The area to scale and present to the user. * @param caption An optional caption which is drawn in the center of the area. */ void setArea(const QRect& area, const QString& caption); /** * Sets the areas which should be scaled and displayed to the user. * All areas will be united and displayed as one big area to the user. * Therefore the areas should be adjecent or overlapping. * * @param areas The areas to display to the user. * @param caption Optional captions to draw in the center of each area. */ void setAreas(const QMap &areas, const QStringList& areaCaptions); /** * Enables or disables drawing of area captions. * * @param value True to draw area captions, false to not draw them. */ void setDrawAreaCaptions(bool value); /** * Enables or disables drawing of the selection area caption. * * @param value True to draw caption, false to not draw it. */ void setDrawSelectionCaption(bool value); /** * Sets the font used to draw all captions. * * @param font The font used for captions. */ void setFont(const QFont& font); /** * Sets the out of bounds margin in pixels or as a percentage. * The out of bounds margin is the amount of pixels, the user is * allowed to drag the selected area outside the bounds of the * displayed area. The margin has to be given as a percentage value * or as a positive value in real size pixels. * * @param margin A percentage (0. - 1.0) or a positive value in pixels. */ void setOutOfBoundsMargin(qreal margin); /** * Selects an area. * * @param selection The area to select. */ - void setSelection(const QRect& selection); + void setSelection(const QRect& selection, bool emitUpdate); /** * Selects an area by area index. This is the index from the list * the widget was initialized with. * * @param areaIndex The list index of the sub-area to select. */ void setSelection(QString output); /** * Sets the widget's target size. This is only a hint for the widget * to determine the approximate size it should target for when scaling the * areas. As long as the ratio does not fit to the ratio of the displayed * area, only one value will be used. The other value will be scaled up * or down to fit the ratio of the displayed area. * * @param size The widget's target size (Default: 400x400) */ void setWidgetTargetSize(const QSize& size); void lockProportions(bool enable); signals: /** * Emitted whenever the selected area changes. */ void selectionChanged(); protected: /** * Overriden QWidget method which captures mouse movements. */ virtual void mouseMoveEvent ( QMouseEvent * event ); /** * Overriden QWidget method which captures mouse button press events. */ virtual void mousePressEvent ( QMouseEvent * event ); /** * Overriden QWidget method which captures mouse button release events. */ virtual void mouseReleaseEvent ( QMouseEvent * event ); /** * Overriden QWidget method which paints the widget. */ virtual void paintEvent(QPaintEvent *event); private: /** * The current dragging mode which determines if the * user is dragging one of the border handles or the * whole area with the mouse. */ enum class DragMode { DragNone, //!< The user is currently not dragging. DragSelectedArea, //!< The user drags the whole selection ara. DragTopHandle, //!< The user drags the top border handle. DragRightHandle, //!< The user drags the right border handle. DragBottomHandle, //!< The user drags the bottom border handle. DragLeftHandle //!< The user drags the left border handle. }; /** * Calculates the size and position of the area which is displayed * to the user according to the given virtual area, a scale factor * and an optional margin. * * @param virtualArea The virtual area to calculate the display area for. * @param scaleFactor The scale factor which is applied to the virtual area. * @param totalDisplayAreaMargin The total display area margin. */ const QRectF calculateDisplayArea(const QRect& virtualArea, qreal scaleFactor, qreal totalDisplayAreaMargin) const; /** * Calculates the size and position of the display sub-areas which * make up the whole display area. * * @param areas The display sub-areas. * @param scaleFactor The scale factor which is applied to the areas. * @param totalDisplayAreaMargin The total display area margin. */ const QList< QRectF > calculateDisplayAreas(const QMap areas, qreal scaleFactor, qreal totalDisplayAreaMargin) const; /** * Calculates the out of bounds margin for the virtual area. * * @param virtualArea The virtual area to calculate the oob margin for. * @param outOfBoundMargin A percentage (0-1.0) or a value in pixels (>1). * * @return The out ouf bounds margin in virtual area pixels. */ qreal calculateOutOfBoundsVirtualAreaMargin(const QRect& virtualArea, qreal outOfBoundsMargin) const; /** * Calculates a scaling factor based on a widget target size and the * given virtual area. * * @param targetSize The target size of this widget. * @param virtualArea The virtual area to calculate the scaling factor for. * @param virtualAreaOutOfBoundsMargin The out of bounds margin of the virtual area. * @param displayAreaExtraMargin An extra margin for the display area. * * @return The scaling factor for the given target size. */ qreal calculateScaleFactor(const QSize& targetSize, const QRect& virtualArea, qreal virtualAreaOutOfBoundsMargin, qreal displayAreaExtraMargin) const; /** * Calculates a scaled version of the given area. * * @param area The area to scale. * @param scaleFactor The scale factor which is applied to the area. * @param margin An optional margin around the display area. * * @return The scaled area. */ const QRectF calculateScaledArea(const QRect& area, qreal scaleFactor, qreal totalDisplayAreaMargin) const; /** * Unscales a scaled area. * * @param area The area to unscale. * @param scaleFactor The scale factor which was applied to the area. * @param margin An optional margin around the display area. * * @return The unscaled area. */ const QRect calculateUnscaledArea(const QRectF& area, qreal scaleFactor, qreal totalDisplayAreaMargin) const; /** * Calculates the size of the virtual area. * * @param areas A list of areas to calculate the virtual area for. * * @return The size of the virtual area as rectangle. */ const QRect calculateVirtualArea(const QMap &areas) const; /** * Returns the total margin of the display area. This is is the out of bounds * margin plus any additional margin which might be applied around the widget. * * @return The total display area margin. */ qreal getTotalDisplayAreaMargin() const; /** * Determines if the user is currently dragging a handle or * the selected area with the mouse. * * @return True if user is dragging, else false. */ bool isUserDragging() const; /** * Paints the captions of the display areas. * * @param painter The painter to use. */ void paintDisplayAreaCaptions(QPainter& painter); /** * Paints the display area and all of its sub-areas. * * @param painter The painter to use. * @param outlineOnly A flag if only the outline should be painted. */ void paintDisplayAreas(QPainter& painter, bool outlineOnly); /** * Paints the drag handles. * * @param painter The painter to use. */ void paintDragHandles(QPainter& painter); /** * Paints the selected area. * * @param painter The painter to use. */ void paintSelectedArea(QPainter& painter, bool outlineOnly); /** * Paints the size of the selected area as string. * * @param painter The painter to sue. */ void paintSelectedAreaCaption(QPainter& painter); /** * Sets up the widget. Can be called anytime to recalculate the display area size. */ void setupWidget(); /** * Recalculates the positions of the drag handles. */ void updateDragHandles(); /** * Updates the mouse cursor according to the mouse's position. * * @param mousePosition The current position of the mouse. */ void updateMouseCursor(const QPoint& mousePosition); /** * Updates the selected area when the user drags it. */ void updateSelectedAreaOnDrag(const QPoint& mousePosition); /** * Updates the selected area when the user is moving it. * * @param mousePosition The current mouse position where the user wants to move the selection to. */ void updateSelectedAreaOnDragArea(const QPoint& mousePosition); /** * Updates the selected area when the user is dragging with the bottom handle. * * @param mousePosition The current mouse position where the user wants to have the new border set. */ void updateSelectedAreaOnDragBottom(const QPoint& mousePosition); /** * Updates the selected area when the user is dragging with the left handle. * * @param mousePosition The current mouse position where the user wants to have the new border set. */ void updateSelectedAreaOnDragLeft(const QPoint& mousePosition); /** * Updates the selected area when the user is dragging with the right handle. * * @param mousePosition The current mouse position where the user wants to have the new border set. */ void updateSelectedAreaOnDragRight(const QPoint& mousePosition); /** * Updates the selected area when the user is dragging with the top handle. * * @param mousePosition The current mouse position where the user wants to have the new border set. */ void updateSelectedAreaOnDragTop(const QPoint& mousePosition); /** * Asserts that the selected area is not wider or higher than the display area. * Updates the selected area accordingly. * * @param fixPositionInsteadOfSize Fix x and y value instead of the width and height of the selection. */ void updateSelectedAreaSize(bool fixPositionInsteadOfSize = false); Q_DECLARE_PRIVATE(AreaSelectionWidget) AreaSelectionWidgetPrivate *const d_ptr; //!< D-Pointer for this class. }; // CLASS } // NAMESPACE #endif // HEADER PROTECTION diff --git a/src/kcmodule/tabletareaselectionview.cpp b/src/kcmodule/tabletareaselectionview.cpp index 9f52f82..456b1cc 100644 --- a/src/kcmodule/tabletareaselectionview.cpp +++ b/src/kcmodule/tabletareaselectionview.cpp @@ -1,289 +1,330 @@ /* * 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 "tabletareaselectionview.h" #include "ui_tabletareaselectionview.h" #include using namespace Wacom; namespace Wacom { class TabletAreaSelectionViewPrivate { public: TabletAreaSelectionViewPrivate() : ui(new Ui::TabletAreaSelectionView) {} ~TabletAreaSelectionViewPrivate() { delete ui; } Ui::TabletAreaSelectionView *ui = nullptr; }; // PRIVATE CLASS } // NAMESPACE TabletAreaSelectionView::TabletAreaSelectionView(QWidget* parent) : QWidget(parent), d_ptr(new TabletAreaSelectionViewPrivate) { setupUi(); } TabletAreaSelectionView::~TabletAreaSelectionView() { delete this->d_ptr; } const TabletArea TabletAreaSelectionView::getSelection() const { Q_D(const TabletAreaSelectionView); return TabletArea(d->ui->areaWidget->getSelection()); } void TabletAreaSelectionView::selectFullTablet() { Q_D(TabletAreaSelectionView); setTabletAreaType(TabletAreaSelectionView::FullTabletArea); d->ui->areaWidget->clearSelection(); } void TabletAreaSelectionView::selectPartOfTablet(const TabletArea &selection) { Q_D(TabletAreaSelectionView); setTabletAreaType(TabletAreaSelectionView::PartialTabletArea); - d->ui->areaWidget->setSelection(selection); + d->ui->areaWidget->setSelection(selection, true); } void TabletAreaSelectionView::select(QString output, bool isDesktop, const TabletArea &tabletSelection) { Q_D(TabletAreaSelectionView); if (isDesktop) { // select full desktop d->ui->screenArea->clearSelection(); } else { // select monitor d->ui->screenArea->setSelection(output); } if(isFullAreaSelection(tabletSelection)) { // full tablet selection selectFullTablet(); } else { // part of tablet selection selectPartOfTablet(tabletSelection); } } void TabletAreaSelectionView::setTrackingModeWarning(bool doShow) { Q_D(TabletAreaSelectionView); d->ui->warningIcon->setVisible(doShow); d->ui->warningLabel->setVisible(doShow); } void TabletAreaSelectionView::setupScreens(const QMap &screenGeometries, const QSize &widgetTargetSize) { Q_D(TabletAreaSelectionView); // disable screen toggling by default d->ui->screenToggleButton->setEnabled(false); // setup screen area d->ui->screenArea->setEnabled(false); d->ui->screenArea->setWidgetTargetSize(widgetTargetSize); d->ui->screenArea->setFont(QFont(QLatin1String("sans"), 8)); d->ui->screenArea->paintBelow = true; if (screenGeometries.count() > 0) { d->ui->screenArea->setDrawAreaCaptions(true); d->ui->screenArea->setDrawSelectionCaption(true); d->ui->screenArea->setAreas(screenGeometries, screenGeometries.keys()); // allow screen toggling if we have more than one screen if (screenGeometries.count() > 1) { d->ui->screenToggleButton->setEnabled(true); } } else { // no valid parameters passed, draw error box d->ui->screenArea->setDrawAreaCaptions(true); d->ui->screenArea->setDrawSelectionCaption(false); d->ui->screenArea->setArea(QRect(0,0,1920,1200), i18n("Internal Error")); // We call this intentionally with no screens from setupUI() qCWarning(KCM) << "Call to TabletAreaSelectionView::setupScreens made with no valid screens."; } // defaults to full selection d->ui->screenArea->clearSelection(); } void TabletAreaSelectionView::setupTablet(const TabletArea &geometry, const QSize& widgetTargetSize) { Q_D(TabletAreaSelectionView); d->ui->areaWidget->setWidgetTargetSize(widgetTargetSize); d->ui->areaWidget->setOutOfBoundsMargin(.1); if (geometry.isValid()) { QString caption = QString::fromLatin1("%1x%2").arg(geometry.width()).arg(geometry.height()); d->ui->areaWidget->setDrawAreaCaptions(true); d->ui->areaWidget->setDrawSelectionCaption(true); d->ui->areaWidget->setArea(geometry, caption); } else { // draw error message d->ui->areaWidget->setDrawAreaCaptions(true); d->ui->areaWidget->setDrawSelectionCaption(false); d->ui->areaWidget->setArea(QRect(0,0,1920,1200), i18n("Internal Error")); qCWarning(KCM) << "Internal error, invalid tablet geometry -" << geometry.toString(); } // defaults to full selection setTabletAreaType(TabletAreaSelectionView::FullTabletArea); } void TabletAreaSelectionView::onCalibrateClicked() { emit signalCalibrateClicked(); } void TabletAreaSelectionView::onForceProportionsClicked() { emit signalSetScreenProportions(); } void TabletAreaSelectionView::onFullTabletSelected(bool checked) { if (!checked) { return; } setTabletAreaType(TabletAreaSelectionView::FullTabletArea); } void TabletAreaSelectionView::onScreenToggle() { emit signalScreenToggle(); } void TabletAreaSelectionView::onTabletAreaSelected(bool checked) { if (!checked) { return; } setTabletAreaType(TabletAreaSelectionView::PartialTabletArea); } void TabletAreaSelectionView::onLockProportionsToggled(bool enabled) { Q_D(TabletAreaSelectionView); d->ui->areaWidget->lockProportions(enabled); } void TabletAreaSelectionView::setSelection(const TabletArea &selection) { if (selection.isValid()) { if (isFullAreaSelection(selection)) { selectFullTablet(); } else { selectPartOfTablet(selection); } } else { selectFullTablet(); } } void TabletAreaSelectionView::setTabletAreaType(TabletAreaSelectionView::TabletAreaType type) { Q_D(TabletAreaSelectionView); d->ui->fullTabletRadioButton->blockSignals(true); d->ui->tabletAreaRadioButton->blockSignals(true); if (type == TabletAreaSelectionView::FullTabletArea) { d->ui->fullTabletRadioButton->setChecked(true); d->ui->tabletAreaRadioButton->setChecked(false); d->ui->areaWidget->clearSelection(); d->ui->areaWidget->setEnabled(false); emit signalFullTabletSelection(); } else { d->ui->tabletAreaRadioButton->setChecked(true); d->ui->fullTabletRadioButton->setChecked(false); d->ui->areaWidget->setEnabled(true); emit signalTabletAreaSelection(); } d->ui->fullTabletRadioButton->blockSignals(false); d->ui->tabletAreaRadioButton->blockSignals(false); } +void TabletAreaSelectionView::onSelectionChanged() +{ + Q_D(TabletAreaSelectionView); + + const auto selection = d->ui->areaWidget->getSelection(); + + d->ui->lineEditX->setText(QString::number(selection.x())); + d->ui->lineEditY->setText(QString::number(selection.y())); + d->ui->lineEditWidth->setText(QString::number(selection.width())); + d->ui->lineEditHeight->setText(QString::number(selection.height())); +} + +void TabletAreaSelectionView::onFineTuneValuesChanged(QString) +{ + Q_D(TabletAreaSelectionView); + bool xvalid = true; + bool yvalid = true; + bool wvalid = true; + bool hvalid = true; + + const QRect newSelection(d->ui->lineEditX->text().toInt(&xvalid), + d->ui->lineEditY->text().toInt(&yvalid), + d->ui->lineEditWidth->text().toInt(&wvalid), + d->ui->lineEditHeight->text().toInt(&hvalid)); + + if (newSelection.isEmpty() || !newSelection.isValid() + || !xvalid || !yvalid || !wvalid || !hvalid) { + return; + } + + d->ui->areaWidget->setSelection(newSelection, false); +} bool TabletAreaSelectionView::isFullAreaSelection(const TabletArea &selection) const { Q_D (const TabletAreaSelectionView); return ( selection.isEmpty() || selection == d->ui->areaWidget->getVirtualArea() ); } void TabletAreaSelectionView::setupUi() { Q_D(TabletAreaSelectionView); d->ui->setupUi(this); d->ui->iconLabel->setPixmap(QIcon::fromTheme(QLatin1String("help-about")).pixmap(QSize(16,16))); d->ui->warningIcon->setPixmap(QIcon::fromTheme(QLatin1String("dialog-warning")).pixmap(QSize(16,16))); d->ui->warningIcon->setVisible(true); d->ui->warningLabel->setVisible(false); + // FIXME: signal-slot editor can't see this signal for some reason + // TODO: rename areaWidget and screenArea, this is confusing + connect(d->ui->areaWidget, &AreaSelectionWidget::selectionChanged, this, &TabletAreaSelectionView::onSelectionChanged); + + connect(d->ui->lineEditX, &QLineEdit::textChanged, this, &TabletAreaSelectionView::onFineTuneValuesChanged); + connect(d->ui->lineEditY, &QLineEdit::textChanged, this, &TabletAreaSelectionView::onFineTuneValuesChanged); + connect(d->ui->lineEditHeight, &QLineEdit::textChanged, this, &TabletAreaSelectionView::onFineTuneValuesChanged); + connect(d->ui->lineEditWidth, &QLineEdit::textChanged, this, &TabletAreaSelectionView::onFineTuneValuesChanged); + // Is this next call, like, fake? setupScreens(QMap(), QSize(200,200)); setupTablet(TabletArea(), QSize(400,400)); } diff --git a/src/kcmodule/tabletareaselectionview.h b/src/kcmodule/tabletareaselectionview.h index 2a4778a..0059935 100644 --- a/src/kcmodule/tabletareaselectionview.h +++ b/src/kcmodule/tabletareaselectionview.h @@ -1,219 +1,223 @@ /* * 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 TABLETAREASELECTIONVIEW_H #define TABLETAREASELECTIONVIEW_H #include "tabletarea.h" #include #include #include #include namespace Wacom { class TabletAreaSelectionViewPrivate; /** * A widget which displays the current screen area selection and lets * the user map this selection to a tablet area. */ class TabletAreaSelectionView : public QWidget { Q_OBJECT public: explicit TabletAreaSelectionView( QWidget* parent = 0 ); virtual ~TabletAreaSelectionView(); /** * @return The current selection as rectangle. */ const TabletArea getSelection() const; /** * Selects all of the tablet. */ void selectFullTablet(); /** * Selects part of the tablet. * * @param selection The part to select, may not be empty. */ void selectPartOfTablet(const TabletArea& selection); /** * Switches to the given screen and selects the given tablet region. * * @param output The name of the screen to switch to. * @param tabletSelection The selection to set on the tablet. */ void select(QString output, bool isDesktop, const TabletArea &tabletSelection); /** * Shows or hides a warning that the current selection is only * available in absolute tracking mode. * * @param doShow If true the warning is displayed, else it is hidden. */ void setTrackingModeWarning(bool doShow); /** * Sets up the screen area widget. * * @param screenGeometries The X11 geometries of the connected screens. * @param widgetTargetSize The target size of the screen area widget. */ void setupScreens(const QMap &screenGeometries, const QSize &widgetTargetSize); /** * Sets up the tablet area widget. * * @param geometry The geometry of the tablet. * @param widgetTargetSize The target size of the tablet area widget. */ void setupTablet( const TabletArea& geometry, const QSize& widgetTargetSize ); public slots: /** * Called by the UI when the user wants to calibrate the current device. */ void onCalibrateClicked(); /** * Called by the UI when the user wants to adjust the selection to the screen proportions. */ void onForceProportionsClicked(); /** * Called by the UI when the user wants to select the full tablet area. */ void onFullTabletSelected(bool checked); /** * Called by the UI when the user wants to toggle the screen. */ void onScreenToggle(); /** * Called by the UI when the user wants to select an area of the tablet. */ void onTabletAreaSelected(bool checked); /** * @brief onLockProportionsToggled * @param enabled */ void onLockProportionsToggled(bool enabled); + void onSelectionChanged(); + + void onFineTuneValuesChanged(QString); + signals: /** * Signals the controller that the user wants to calibrate the tablet. */ void signalCalibrateClicked(); /** * Signals the controller that the user selected the full tablet area. */ void signalFullTabletSelection(); /** * Signals the controller that the user wants to toggle the screen. */ void signalScreenToggle(); /** * Signals the controller that the user wants to set screen proportions. */ void signalSetScreenProportions(); /** * Signals the controller that the user selected a tablet area. */ void signalTabletAreaSelection(); protected: /** * The available mapping types for the tablet. */ enum TabletAreaType { FullTabletArea, //!< Enables full desktop selection. PartialTabletArea //!< Enables area selection. }; /** * Sets a selection on the tablet based on the given geometry. * This does not update any other widgets. It only tells the * area widget to select the specified area. However a check * is done if the selection is valid. If it is invalid, the full * area will be selected. * * @param selection The geometry of the new selection. */ void setSelection(const TabletArea& selection); /** * Sets the given mapping type and updates the widgets * and the selection. * * @param type The new mapping type. */ void setTabletAreaType(TabletAreaType type); private: /** * Checks if the given selection selects the full tablet area. * * @param selection The selection to check. * * @return True if the given selection selects the full tablet area, else false. */ bool isFullAreaSelection(const TabletArea& selection) const; /** * Sets up this widget. Must only be called once by the constructor. */ void setupUi(); Q_DECLARE_PRIVATE(TabletAreaSelectionView) TabletAreaSelectionViewPrivate *const d_ptr; //!< D-Pointer for this class. }; // CLASS } // NAMESPACE #endif // HEADER PROTECTION diff --git a/src/kcmodule/tabletareaselectionview.ui b/src/kcmodule/tabletareaselectionview.ui index 6f5e10b..b2436a9 100644 --- a/src/kcmodule/tabletareaselectionview.ui +++ b/src/kcmodule/tabletareaselectionview.ui @@ -1,371 +1,455 @@ TabletAreaSelectionView 0 0 669 312 16 16 16 16 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop The tablet area defines how the screen space is mapped to your tablet. For each screen a different tablet area can be selected. true Screen Qt::AlignCenter true 0 0 Toggle between fullscreen and each single screen. Toggle Screen Select the valid tablet area used for the selected screen space. Map Screen To &Full Tablet true &Tablet Area Set the tablet area proportional to the selected screen area. Set Screen Proportions Calibrate Qt::Vertical - - QSizePolicy::Expanding - 1 5 Tablet 0 0 0 0 16 16 16 16 This mapping can only be applied in absolute tracking mode. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true Lock proportions .. true + + + + Tablet area fine tuning + + + + + + + 0 + 0 + + + + Width + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Horizontal + + + + + + + + 0 + 0 + + + + Left margin + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Vertical + + + + + + + + 0 + 0 + + + + Top margin + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Height + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + Qt::Vertical QSizePolicy::MinimumExpanding 0 0 Wacom::AreaSelectionWidget QWidget
areaselectionwidget.h
1
calibrateButton clicked() TabletAreaSelectionView onCalibrateClicked() 123 282 199 149 forceProportionsButton clicked() TabletAreaSelectionView onForceProportionsClicked() 123 253 199 149 fullTabletRadioButton toggled(bool) TabletAreaSelectionView onFullTabletSelected(bool) 123 195 199 149 tabletAreaRadioButton toggled(bool) TabletAreaSelectionView onTabletAreaSelected(bool) 123 224 199 149 screenToggleButton clicked() TabletAreaSelectionView onScreenToggle() 150 96 299 130 buttonLockProportions toggled(bool) TabletAreaSelectionView onLockProportionsToggled(bool) 496 186 334 155 onCalibrateClicked() onForceProportionsClicked() onFullTabletSelected(bool) onTabletAreaSelected(bool) onScreenToggle() onLockProportionsToggled(bool)