Merge pull request #16639 from WandererFan/balloonDrag15388

[TD]Balloon origin drag modifiers (fix #15388)
This commit is contained in:
Yorik van Havre
2024-09-30 17:40:23 +02:00
committed by GitHub
10 changed files with 356 additions and 50 deletions

View File

@@ -612,3 +612,32 @@ double Preferences::SnapLimitFactor()
}
//! returns the key combination that simulates multiple selection. Traditionally Ctrl+pick, as that
//! is how QGraphicsScene implements multiple selection. This method is likely to only be used by
//! developers.
Qt::KeyboardModifiers Preferences::multiselectModifiers()
{
uint iModifiers = getPreferenceGroup("General")->GetUnsigned("MultiselectModifiers", (uint)Qt::ControlModifier);
return (Qt::KeyboardModifiers)iModifiers;
// Qt::KeyboardModifiers testMods = Qt::ControlModifier;
// return testMods;
}
//! returns the key combination that modifies Balloon drag behaviour so that the bubble and leader
//! are moved together. Traditionally Ctrl+drag, but that can be in conflict with multi selection.
Qt::KeyboardModifiers Preferences::balloonDragModifiers()
{
uint iModifiers = getPreferenceGroup("General")->GetUnsigned("BalloonDragModifier", (uint)Qt::ControlModifier);
return (Qt::KeyboardModifiers)iModifiers;
// Qt::KeyboardModifiers testMods = Qt::ShiftModifier | Qt::ControlModifier;
// return testMods;
}
void Preferences::setBalloonDragModifiers(Qt::KeyboardModifiers newModifiers)
{
getPreferenceGroup("General")->SetUnsigned("BalloonDragModifier", (uint)newModifiers);
}

View File

@@ -23,6 +23,7 @@
#ifndef Preferences_h_
#define Preferences_h_
#include <Qt>
#include <string>
#include <Base/Parameter.h>
@@ -141,6 +142,11 @@ public:
static bool SnapViews();
static double SnapLimitFactor();
static Qt::KeyboardModifiers multiselectModifiers();
static Qt::KeyboardModifiers balloonDragModifiers();
static void setBalloonDragModifiers(Qt::KeyboardModifiers newModifiers);
};

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>424</height>
<width>700</width>
<height>810</height>
</rect>
</property>
<property name="windowTitle">
@@ -443,6 +443,89 @@ can be a performance penalty in complex models.</string>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gbBehaviour">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Some combinations of OS and Navigation style key bindings may conflict with the default modifier keys for Ballon dragging and View snapping override. You can make adjustments here to find a non-conflicting key binding.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="title">
<string>Behaviour Overrides</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QCheckBox" name="cbBalloonDefault">
<property name="toolTip">
<string>Check this box to use the default modifier keys. Uncheck this box to set a different key combination.</string>
</property>
<property name="text">
<string>Use Default</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Balloon Drag</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="cbBalloonAlt">
<property name="toolTip">
<string>Check this box to include the Alt key in the modifiers.</string>
</property>
<property name="text">
<string>Alt</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="cbBalloonShift">
<property name="toolTip">
<string>Check this box to include the Shift key in the modifiers.</string>
</property>
<property name="text">
<string>Shift</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="cbBalloonMeta">
<property name="toolTip">
<string>Check this box to include the Meta/Start/Super key in the modifiers.</string>
</property>
<property name="text">
<string>Meta</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="cbBalloonControl">
<property name="toolTip">
<string>Check this box to include the Control key in the modifiers.</string>
</property>
<property name="text">
<string>Control</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label_17">
<property name="font">
@@ -469,8 +552,8 @@ can be a performance penalty in complex models.</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>17</width>
<height>1</height>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>

View File

@@ -24,17 +24,21 @@
#include "PreCompiled.h"
#include <Mod/TechDraw/App/Preferences.h>
#include "DlgPrefsTechDrawAdvancedImp.h"
#include "ui_DlgPrefsTechDrawAdvanced.h"
using namespace TechDrawGui;
using namespace TechDraw;
DlgPrefsTechDrawAdvancedImp::DlgPrefsTechDrawAdvancedImp( QWidget* parent )
: PreferencePage( parent )
, ui(new Ui_DlgPrefsTechDrawAdvancedImp)
{
ui->setupUi(this);
makeBalloonBoxConnections();
}
DlgPrefsTechDrawAdvancedImp::~DlgPrefsTechDrawAdvancedImp()
@@ -58,8 +62,40 @@ void DlgPrefsTechDrawAdvancedImp::saveSettings()
ui->cbAutoCorrectRefs->onSave();
ui->cbNewFaceFinder->onSave();
ui->sbScrubCount->onSave();
saveBalloonOverride();
}
void DlgPrefsTechDrawAdvancedImp::saveBalloonOverride()
{
if (ui->cbBalloonDefault->isChecked()) {
Preferences::setBalloonDragModifiers(Qt::ControlModifier);
return;
}
Qt::KeyboardModifiers result{Qt::NoModifier};
if (ui->cbBalloonShift->isChecked()) {
result |= Qt::ShiftModifier;
}
if (ui->cbBalloonControl->isChecked()) {
result |= Qt::ControlModifier;
}
if (ui->cbBalloonAlt->isChecked()) {
result |= Qt::AltModifier;
}
if (ui->cbBalloonMeta->isChecked()) {
result |= Qt::MetaModifier;
}
Preferences::setBalloonDragModifiers(result);
}
void DlgPrefsTechDrawAdvancedImp::loadSettings()
{
ui->cbDetectFaces->onRestore();
@@ -76,18 +112,116 @@ void DlgPrefsTechDrawAdvancedImp::loadSettings()
ui->cbAutoCorrectRefs->onRestore();
ui->cbNewFaceFinder->onRestore();
ui->sbScrubCount->onRestore();
loadBalloonOverride();
}
void DlgPrefsTechDrawAdvancedImp::loadBalloonOverride()
{
uint prefOverride = Preferences::balloonDragModifiers();
if (prefOverride == Qt::ControlModifier) {
// default case
ui->cbBalloonDefault->setChecked(true);
clearBalloonOptions();
enableBalloonOptions(false);
return;
}
ui->cbBalloonDefault->setChecked(false);
enableBalloonOptions(true);
if (flagsContainValue(prefOverride, Qt::ShiftModifier)) {
ui->cbBalloonShift->setChecked(true);
}
if (flagsContainValue(prefOverride, Qt::ControlModifier)) {
ui->cbBalloonControl->setChecked(true);
}
if (flagsContainValue(prefOverride, Qt::AltModifier)) {
ui->cbBalloonAlt->setChecked(true);
}
if (flagsContainValue(prefOverride, Qt::MetaModifier)) {
ui->cbBalloonMeta->setChecked(true);
}
}
//! true if bit pattern of value is found in flags.
bool DlgPrefsTechDrawAdvancedImp::flagsContainValue(uint flags, uint value)
{
uint matchResult = flags & value;
if (matchResult == value) {
return true;
}
return false;
}
void DlgPrefsTechDrawAdvancedImp::clearBalloonOptions()
{
ui->cbBalloonShift->setChecked(false);
ui->cbBalloonControl->setChecked(false);
ui->cbBalloonAlt->setChecked(false);
ui->cbBalloonMeta->setChecked(false);
}
void DlgPrefsTechDrawAdvancedImp::enableBalloonOptions(bool newState)
{
ui->cbBalloonShift->setEnabled(newState);
ui->cbBalloonControl->setEnabled(newState);
ui->cbBalloonAlt->setEnabled(newState);
ui->cbBalloonMeta->setEnabled(newState);
}
void DlgPrefsTechDrawAdvancedImp::slotBalloonBoxChecked()
{
if (ui->cbBalloonDefault->isChecked()) {
clearBalloonOptions();
enableBalloonOptions(false);
} else {
enableBalloonOptions(true);
}
}
void DlgPrefsTechDrawAdvancedImp::makeBalloonBoxConnections()
{
connect(ui->cbBalloonDefault,
qOverload<int>(&QCheckBox::stateChanged),
this,
&DlgPrefsTechDrawAdvancedImp::slotBalloonBoxChecked);
connect(ui->cbBalloonShift,
qOverload<int>(&QCheckBox::stateChanged),
this,
&DlgPrefsTechDrawAdvancedImp::slotBalloonBoxChecked);
connect(ui->cbBalloonControl,
qOverload<int>(&QCheckBox::stateChanged),
this,
&DlgPrefsTechDrawAdvancedImp::slotBalloonBoxChecked);
connect(ui->cbBalloonAlt,
qOverload<int>(&QCheckBox::stateChanged),
this,
&DlgPrefsTechDrawAdvancedImp::slotBalloonBoxChecked);
connect(ui->cbBalloonMeta,
qOverload<int>(&QCheckBox::stateChanged),
this,
&DlgPrefsTechDrawAdvancedImp::slotBalloonBoxChecked);
}
/**
* Sets the strings of the subwidgets using the current language.
*/
void DlgPrefsTechDrawAdvancedImp::changeEvent(QEvent *e)
void DlgPrefsTechDrawAdvancedImp::changeEvent(QEvent *event)
{
if (e->type() == QEvent::LanguageChange) {
if (event->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
}
else {
QWidget::changeEvent(e);
QWidget::changeEvent(event);
}
}

View File

@@ -44,7 +44,19 @@ public:
protected:
void saveSettings() override;
void loadSettings() override;
void changeEvent(QEvent *e) override;
void changeEvent(QEvent *event) override;
void loadBalloonOverride();
void saveBalloonOverride();
void clearBalloonOptions();
static bool flagsContainValue(uint flags, uint value);
void makeBalloonBoxConnections();
void slotBalloonBoxChecked();
void enableBalloonOptions(bool newState);
private:
std::unique_ptr<Ui_DlgPrefsTechDrawAdvancedImp> ui;

View File

@@ -401,6 +401,9 @@ Base::Vector3d QGIView::projItemPagePos(DrawViewPart* item)
void QGIView::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
// this is never called for balloons (and dimensions?) because the label objects do not
// inherit from QGIView, but directly from QGraphicsItem. - wf
Qt::KeyboardModifiers originalModifiers = event->modifiers();
if (event->button()&Qt::LeftButton) {
m_multiselectActivated = false;

View File

@@ -26,6 +26,7 @@
# include <cmath>
# include <string>
# include <QGuiApplication>
# include <QGraphicsScene>
# include <QGraphicsSceneMouseEvent>
# include <QPaintDevice>
@@ -55,6 +56,7 @@
#include "ViewProviderViewPart.h"
#include "ZVALUE.h"
#include "DrawGuiUtil.h"
#include "QGSPage.h"
//TODO: hide the Qt coord system (+y down).
@@ -66,8 +68,8 @@ using DGU = DrawGuiUtil;
QGIBalloonLabel::QGIBalloonLabel()
{
m_ctrl = false;
m_drag = false;
m_originDrag = false;
m_dragging = false;
setCacheMode(QGraphicsItem::NoCache);
setFlag(ItemSendsGeometryChanges, true);
@@ -98,8 +100,8 @@ QVariant QGIBalloonLabel::itemChange(GraphicsItemChange change, const QVariant&
update();
}
else if (change == ItemPositionHasChanged && scene()) {
if (m_drag) {
Q_EMIT dragging(m_ctrl);
if (m_dragging) {
Q_EMIT dragging(m_originDrag);
}
}
@@ -108,11 +110,22 @@ QVariant QGIBalloonLabel::itemChange(GraphicsItemChange change, const QVariant&
void QGIBalloonLabel::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
m_ctrl = false;
m_drag = true;
if (event->modifiers() & Qt::ControlModifier) {
m_ctrl = true;
m_originDrag = false;
m_dragging = true;
if (event->button() != Qt::LeftButton) {
QGraphicsItem::mousePressEvent(event);
return;
}
if (QGSPage::cleanModifierList(event->modifiers()) == Preferences::balloonDragModifiers()) {
if (!PreferencesGui::multiSelection() ||
Preferences::multiselectModifiers() != Preferences::balloonDragModifiers()) {
// multiselect does not apply or does not conflict, so treat this is an origin drag
m_originDrag = true;
}
}
QGraphicsItem::mousePressEvent(event);
}
@@ -123,8 +136,8 @@ void QGIBalloonLabel::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
Q_EMIT dragFinished();
}
}
m_ctrl = false;
m_drag = false;
m_originDrag = false;
m_dragging = false;
QGraphicsItem::mouseReleaseEvent(event);
}
@@ -234,8 +247,6 @@ QGIViewBalloon::QGIViewBalloon()
: dvBalloon(nullptr), hasHover(false), m_lineWidth(0.0), m_obtuse(false), parent(nullptr),
m_dragInProgress(false)
{
m_ctrl = false;
setHandlesChildEvents(false);
setFlag(QGraphicsItem::ItemIsMovable, false);
setCacheMode(QGraphicsItem::NoCache);
@@ -443,9 +454,8 @@ void QGIViewBalloon::updateBalloon(bool obtuse)
balloonLabel->setPosFromCenter(x, -y);
}
void QGIViewBalloon::balloonLabelDragged(bool ctrl)
void QGIViewBalloon::balloonLabelDragged(bool originDrag)
{
m_ctrl = ctrl;
auto dvb(dynamic_cast<TechDraw::DrawViewBalloon*>(getViewObject()));
if (!dvb) {
return;
@@ -453,7 +463,7 @@ void QGIViewBalloon::balloonLabelDragged(bool ctrl)
if (!m_dragInProgress) {//first drag movement
m_dragInProgress = true;
if (ctrl) {//moving whole thing, remember Origin offset from Bubble
if (originDrag) {//moving whole thing, remember Origin offset from Bubble
m_saveOriginOffset = dvb->getOriginOffset();
m_saveOrigin = DU::toVector3d(arrow->pos());
m_savePosition = DU::toVector3d(balloonLabel->pos());
@@ -461,7 +471,7 @@ void QGIViewBalloon::balloonLabelDragged(bool ctrl)
}
// store if origin is also moving to be able to later calc new origin and update feature
if (ctrl) {
if (originDrag) {
m_originDragged = true;
}
@@ -595,10 +605,10 @@ void QGIViewBalloon::draw()
drawBalloon(false);
}
void QGIViewBalloon::drawBalloon(bool dragged)
void QGIViewBalloon::drawBalloon(bool originDrag)
{
if ((!dragged) && m_dragInProgress) {
// TODO there are 2 drag status variables. m_dragInProgress appears to be the one to use?
if ((!originDrag) && m_dragInProgress) {
// TODO there are 2 drag status variables. m_draggingInProgress appears to be the one to use?
// dragged shows false while drag is still in progress.
return;
}
@@ -630,7 +640,7 @@ void QGIViewBalloon::drawBalloon(bool dragged)
float arrowTipX;
Base::Vector3d arrowTipPosInParent;
bool isDragging = dragged || m_dragInProgress;
bool isDragging = originDrag || m_dragInProgress;
Base::Vector3d labelPos;
getBalloonPoints(balloon, refObj, isDragging, labelPos, arrowTipPosInParent);
arrowTipX = arrowTipPosInParent.x;

View File

@@ -158,8 +158,8 @@ private:
QColor m_colNormal;
bool m_ctrl;
bool m_drag;
bool m_originDrag;
bool m_dragging;
};
//*******************************************************************
@@ -220,7 +220,7 @@ public Q_SLOTS:
protected:
void draw() override;
void drawBalloon(bool dragged = false);
void drawBalloon(bool originDrag = false);
QVariant itemChange(GraphicsItemChange change, const QVariant& value) override;
virtual void setSvgPens();
virtual void setPens();
@@ -248,7 +248,6 @@ private:
bool m_dragInProgress;
bool m_originDragged = false;
bool m_ctrl;
Base::Vector3d m_saveOriginOffset;
Base::Vector3d m_saveOrigin;
Base::Vector3d m_savePosition;

View File

@@ -22,6 +22,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QApplication>
#include <QDomDocument>
#include <QFile>
#include <QGraphicsSceneEvent>
@@ -110,30 +111,20 @@ QGSPage::QGSPage(ViewProviderPage* vpPage, QWidget* parent)
void QGSPage::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
constexpr int QGITemplateType{QGraphicsItem::UserType + 150};
constexpr int QGIDrawingTemplateType{QGraphicsItem::UserType + 151};
constexpr int QGISVGTemplateType{QGraphicsItem::UserType + 153};
// type 13 is the itemUnderMouse on a page outside of any views. It is not
// the template or background or foreground. QGraphicsItem type = 13 is not
// documented and not found in QGraphicsItem.h.
constexpr int MysteryType{13};
Qt::KeyboardModifiers originalModifiers = event->modifiers();
auto itemUnderMouse = itemAt(event->scenePos().x(), event->scenePos().y(), QTransform());
if (!itemUnderMouse ||
itemUnderMouse->type() == QGITemplateType ||
itemUnderMouse->type() == QGIDrawingTemplateType ||
itemUnderMouse->type() == QGISVGTemplateType ||
itemUnderMouse->type() == MysteryType) {
// click without item clears selection
itemClearsSelection(itemUnderMouse->type()) ) {
Gui::Selection().clearSelection();
QGraphicsScene::mousePressEvent(event);
return;
}
if (event->button() == Qt::LeftButton && PreferencesGui::multiSelection()) {
event->setModifiers(originalModifiers | Qt::ControlModifier);
if (event->button() == Qt::LeftButton &&
PreferencesGui::multiSelection() &&
(cleanModifierList(QApplication::keyboardModifiers()) == Preferences::multiselectModifiers()) ) {
event->setModifiers(originalModifiers | Preferences::multiselectModifiers());
}
QGraphicsScene::mousePressEvent(event);
@@ -147,10 +138,47 @@ void QGSPage::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
}
QGraphicsScene::mouseReleaseEvent(event);
}
// what does this do? the event has already been propagated so this will have
// no effect?
event->setModifiers(originalModifiers);
//! returns true if clicking on the item should clear the selection
bool QGSPage::itemClearsSelection(int itemTypeIn)
{
// type 13 is the itemUnderMouse on a page outside of any views. It is not
// the template or background or foreground. QGraphicsItem type = 13 is not
// documented and not found in QGraphicsItem.h.
const std::vector<int> ClearingTypes { 13, // MysteryType
QGraphicsItem::UserType + 150, // QGITemplateType
QGraphicsItem::UserType + 151, // QGIDrawingTemplateType
QGraphicsItem::UserType + 153 }; // QGISVGTemplateType
for (auto& type : ClearingTypes) {
if (itemTypeIn == type) {
return true;
}
}
return false;
}
//! return only the modifiers that are relevant to snapping/balloon drag.
//! this is a substitute for !modifiers (ie no modifiers in use) since keypad or group modifiers
//! (which don't apply to snapping/dragging) would give a misleading result.
Qt::KeyboardModifiers QGSPage::cleanModifierList(Qt::KeyboardModifiers mods)
{
if (!mods) {
return mods;
}
// remove misleading modifiers if present
auto newMods = mods;
if (newMods & Qt::KeypadModifier) {
newMods = newMods & ~Qt::KeypadModifier;
}
if (newMods & Qt::GroupSwitchModifier) {
newMods = newMods & ~Qt::GroupSwitchModifier;
}
return newMods;
}

View File

@@ -147,6 +147,8 @@ public:
void setBalloonGroups();
void setLeaderParentage();
static bool itemClearsSelection(int itemTypeIn);
static Qt::KeyboardModifiers cleanModifierList(Qt::KeyboardModifiers mods);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;