Files
leocad/common/lc_viewwidget.cpp
T
Leonardo Zide c6dd2c45c1 Fix keyboard focus after dropping parts from floating docks
Dragging a part from a floating Parts window can leave that window active after the drop. Setting focus on the model view alone does not activate its window, so movement shortcuts remain in the Parts list until the model is clicked.

Activate the receiving window before focusing the view after accepted part or color drops so keyboard commands can reach the model immediately.

Fixes #1040.
2026-10-23 14:42:54 -07:00

382 lines
7.9 KiB
C++

#include "lc_global.h"
#include "lc_viewwidget.h"
#include "lc_glextensions.h"
#include "project.h"
#include "lc_library.h"
#include "lc_application.h"
#include "lc_mainwindow.h"
#include "lc_context.h"
#include "lc_view.h"
#include "lc_texture.h"
#include "lc_mesh.h"
#include "lc_profile.h"
#include "lc_previewwidget.h"
lcViewWidget::lcViewWidget(QWidget* Parent, lcView* View)
: QOpenGLWidget(Parent), mView(View)
{
mView->SetWidget(this);
setMouseTracking(true);
if (View->GetViewType() == lcViewType::View)
{
setFocusPolicy(Qt::StrongFocus);
setAcceptDrops(true);
}
}
lcViewWidget::~lcViewWidget()
{
if (context())
makeCurrent();
mView.reset();
if (context())
doneCurrent();
}
QSize lcViewWidget::sizeHint() const
{
return mPreferredSize.isEmpty() ? QOpenGLWidget::sizeHint() : mPreferredSize;
}
lcView* lcViewWidget::GetView() const
{
return mView.get();
}
void lcViewWidget::SetView(lcView* View)
{
if (context())
makeCurrent();
if (View)
{
if (context())
{
View->mContext->SetGLContext(context(), this);
}
View->SetWidget(this);
const float Scale = GetDeviceScale();
View->SetSize(width() * Scale, height() * Scale);
if (hasFocus())
View->SetFocus(true);
}
mView = std::unique_ptr<lcView>(View);
}
void lcViewWidget::UpdateMousePosition()
{
QPoint MousePosition = mapFromGlobal(QCursor::pos());
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MousePosition.x() * DeviceScale, mView->GetHeight() - MousePosition.y() * DeviceScale - 1);
mView->SetMouseModifiers(QApplication::keyboardModifiers());
}
void lcViewWidget::initializeGL()
{
mView->mContext->SetGLContext(context(), this);
}
void lcViewWidget::resizeGL(int Width, int Height)
{
const float Scale = GetDeviceScale();
mView->SetSize(Width * Scale, Height * Scale);
}
void lcViewWidget::paintGL()
{
mView->OnDraw();
}
bool lcViewWidget::event(QEvent* Event)
{
if (Event->type() == QEvent::NativeGesture)
{
QNativeGestureEvent* GestureEvent = static_cast<QNativeGestureEvent*>(Event);
switch (GestureEvent->gestureType())
{
case Qt::ZoomNativeGesture:
mView->Zoom(GestureEvent->value() * 100.0f);
break;
case Qt::SmartZoomNativeGesture:
mView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false);
break;
default:
break;
}
}
return QOpenGLWidget::event(Event);
}
void lcViewWidget::focusInEvent(QFocusEvent* FocusEvent)
{
if (mView)
mView->SetFocus(true);
QOpenGLWidget::focusInEvent(FocusEvent);
}
void lcViewWidget::focusOutEvent(QFocusEvent* FocusEvent)
{
if (mView)
mView->SetFocus(false);
QOpenGLWidget::focusOutEvent(FocusEvent);
}
void lcViewWidget::keyPressEvent(QKeyEvent* KeyEvent)
{
if (KeyEvent->key() == Qt::Key_Control || KeyEvent->key() == Qt::Key_Shift)
{
mView->SetMouseModifiers(KeyEvent->modifiers());
mView->UpdateCursor();
}
QOpenGLWidget::keyPressEvent(KeyEvent);
}
void lcViewWidget::keyReleaseEvent(QKeyEvent* KeyEvent)
{
if (KeyEvent->key() == Qt::Key_Control || KeyEvent->key() == Qt::Key_Shift)
{
mView->SetMouseModifiers(KeyEvent->modifiers());
mView->UpdateCursor();
}
QOpenGLWidget::keyReleaseEvent(KeyEvent);
}
void lcViewWidget::mousePressEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
switch (MouseEvent->button())
{
case Qt::LeftButton:
mView->OnLeftButtonDown();
break;
case Qt::MiddleButton:
mView->OnMiddleButtonDown();
break;
case Qt::RightButton:
mView->OnRightButtonDown();
break;
case Qt::BackButton:
mView->OnBackButtonDown();
break;
case Qt::ForwardButton:
mView->OnForwardButtonDown();
break;
default:
break;
}
}
void lcViewWidget::mouseReleaseEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
switch (MouseEvent->button())
{
case Qt::LeftButton:
mView->OnLeftButtonUp();
break;
case Qt::MiddleButton:
mView->OnMiddleButtonUp();
break;
case Qt::RightButton:
mView->OnRightButtonUp();
break;
case Qt::BackButton:
mView->OnBackButtonUp();
break;
case Qt::ForwardButton:
mView->OnForwardButtonUp();
break;
default:
break;
}
}
void lcViewWidget::mouseDoubleClickEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
switch (MouseEvent->button())
{
case Qt::LeftButton:
mView->OnLeftButtonDoubleClick();
break;
default:
break;
}
}
void lcViewWidget::mouseMoveEvent(QMouseEvent* MouseEvent)
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1);
mView->SetMouseModifiers(MouseEvent->modifiers());
mView->OnMouseMove();
}
void lcViewWidget::wheelEvent(QWheelEvent* WheelEvent)
{
if (WheelEvent->source() == Qt::MouseEventSynthesizedBySystem)
{
switch (WheelEvent->phase())
{
case Qt::NoScrollPhase:
break;
case Qt::ScrollBegin:
mView->StartPanGesture();
WheelEvent->accept();
return;
case Qt::ScrollUpdate:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
case Qt::ScrollMomentum:
#endif
mView->UpdatePanGesture(WheelEvent->pixelDelta().x(), -WheelEvent->pixelDelta().y());
WheelEvent->accept();
return;
case Qt::ScrollEnd:
mView->EndPanGesture(true);
WheelEvent->accept();
return;
}
}
if (WheelEvent->angleDelta().y() == 0)
{
WheelEvent->ignore();
return;
}
float DeviceScale = GetDeviceScale();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
mView->SetMousePosition(WheelEvent->position().x() * DeviceScale, mView->GetHeight() - WheelEvent->position().y() * DeviceScale - 1);
#else
mView->SetMousePosition(WheelEvent->x() * DeviceScale, mView->GetHeight() - WheelEvent->y() * DeviceScale - 1);
#endif
mView->SetMouseModifiers(WheelEvent->modifiers());
mWheelAccumulator += WheelEvent->angleDelta().y();
int Steps = mWheelAccumulator / 8;
if (Steps)
{
mView->OnMouseWheel(Steps / 15);
mWheelAccumulator -= Steps * 8;
}
WheelEvent->accept();
}
void lcViewWidget::leaveEvent(QEvent* Event)
{
mView->OnMouseLeave();
QOpenGLWidget::leaveEvent(Event);
}
void lcViewWidget::dragEnterEvent(QDragEnterEvent* DragEnterEvent)
{
const QMimeData* MimeData = DragEnterEvent->mimeData();
if (MimeData->hasFormat("application/vnd.leocad-part"))
{
DragEnterEvent->acceptProposedAction();
mView->BeginDrag(lcDragState::Piece);
return;
}
else if (MimeData->hasFormat("application/vnd.leocad-color"))
{
DragEnterEvent->acceptProposedAction();
mView->BeginDrag(lcDragState::Color);
return;
}
DragEnterEvent->ignore();
}
void lcViewWidget::dragLeaveEvent(QDragLeaveEvent* DragLeaveEvent)
{
mView->EndDrag(false);
DragLeaveEvent->accept();
}
void lcViewWidget::dragMoveEvent(QDragMoveEvent* DragMoveEvent)
{
const QMimeData* MimeData = DragMoveEvent->mimeData();
if (MimeData->hasFormat("application/vnd.leocad-part") || MimeData->hasFormat("application/vnd.leocad-color"))
{
float DeviceScale = GetDeviceScale();
mView->SetMousePosition(DragMoveEvent->pos().x() * DeviceScale, mView->GetHeight() - DragMoveEvent->pos().y() * DeviceScale - 1);
mView->SetMouseModifiers(DragMoveEvent->keyboardModifiers());
mView->OnMouseMove();
DragMoveEvent->accept();
return;
}
QOpenGLWidget::dragMoveEvent(DragMoveEvent);
}
void lcViewWidget::dropEvent(QDropEvent* DropEvent)
{
const QMimeData* MimeData = DropEvent->mimeData();
if (MimeData->hasFormat("application/vnd.leocad-part") || MimeData->hasFormat("application/vnd.leocad-color"))
{
mView->EndDrag(true);
window()->activateWindow();
setFocus(Qt::MouseFocusReason);
DropEvent->accept();
return;
}
QOpenGLWidget::dropEvent(DropEvent);
}