fix(panel): 暂存优先模式;工厂自身接收拖拽;去掉 drop 提示

- 暂存区非空且未拖拽时只显示暂存列表,隐藏传送门与内容工厂并收窄窗口
- 内容工厂自身区域拖入也会展开动作
- 面板矩形改用屏幕可用区 + 边距计算(layer-shell 下 mapToGlobal 不可靠)
- 离开概览只复位传送门状态,不关闭面板;125ms
- 移除“在哪里 drop”提示
This commit is contained in:
shenmo
2026-10-30 22:00:39 +08:00
parent 3b92202f2d
commit 630ca6cadc
8 changed files with 104 additions and 6 deletions
+4
View File
@@ -88,6 +88,9 @@ bool App::init(bool daemon, bool forceShow, bool showTodo, bool showChat)
return;
}
m_dragging = true;
if (m_panel) {
m_panel->setDragging(true);
}
if (!m_model->isEmpty()) {
if (m_panel && m_panel->isVisible()) {
m_panel->suppressPortalIfUnderCursor();
@@ -107,6 +110,7 @@ bool App::init(bool daemon, bool forceShow, bool showTodo, bool showChat)
m_dragging = false;
if (m_panel) {
m_panel->stopPortalSuppression();
m_panel->setDragging(false);
}
if (m_model->isEmpty() && m_panel && m_panel->isVisible()) {
m_panel->dismiss();
-3
View File
@@ -1281,9 +1281,6 @@ void ChatWindow::startConversationWith(const QString &text, const QStringList &f
}
}
m_input->setFocus();
m_status->setText(tr("拖到左侧空白处=新对话,拖到左侧会话=追加到该会话,拖到右侧对话区=发给当前会话"));
m_status->show();
}
void ChatWindow::activateForAsk()
+39
View File
@@ -317,6 +317,45 @@ void ContentFactory::paintEvent(QPaintEvent *event)
painter.drawPath(path);
}
void ContentFactory::dragEnterEvent(QDragEnterEvent *event)
{
if (!event->mimeData() ||
!(event->mimeData()->hasUrls() || event->mimeData()->hasText() ||
event->mimeData()->hasImage())) {
event->ignore();
return;
}
Q_EMIT dragContent(event->mimeData());
Q_EMIT dragActivity();
event->acceptProposedAction();
}
void ContentFactory::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData() &&
(event->mimeData()->hasUrls() || event->mimeData()->hasText() ||
event->mimeData()->hasImage())) {
Q_EMIT dragContent(event->mimeData());
Q_EMIT dragActivity();
event->acceptProposedAction();
return;
}
event->ignore();
}
void ContentFactory::dragLeaveEvent(QDragLeaveEvent *event)
{
Q_UNUSED(event)
Q_EMIT dragActivity();
}
void ContentFactory::dropEvent(QDropEvent *event)
{
if (event->mimeData()) {
event->acceptProposedAction();
}
}
bool ContentFactory::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
+5
View File
@@ -33,6 +33,7 @@ signals:
void actionRequested(const QString &id, const DropContent &content);
void heightChanged();
void dragActivity();
void dragContent(const QMimeData *mime);
void askRequested();
void askDropped(const QMimeData *mime);
@@ -42,6 +43,10 @@ public:
protected:
void paintEvent(QPaintEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dropEvent(QDropEvent *event) override;
private:
void rebuild();
+8
View File
@@ -50,6 +50,9 @@ PortalClient::PortalClient(QObject *parent)
bus.connect(QString::fromLatin1(kService), QString::fromLatin1(kPath),
QString::fromLatin1(kInterface), QStringLiteral("PortalDropped"), this,
SLOT(onDropped(QString, bool)));
bus.connect(QString::fromLatin1(kService), QString::fromLatin1(kPath),
QString::fromLatin1(kInterface), QStringLiteral("PortalClosed"), this,
SLOT(onPortalClosed()));
}
bool PortalClient::beginPortal(const QRect &panelRect)
@@ -93,6 +96,11 @@ void PortalClient::onDragStarted(const QString &mimeTypes)
Q_EMIT dragStarted(mimeTypes);
}
void PortalClient::onPortalClosed()
{
Q_EMIT portalClosed();
}
void PortalClient::onDragEnded()
{
Q_EMIT dragEnded();
+2
View File
@@ -33,11 +33,13 @@ public:
signals:
void dragStarted(const QString &mimeTypes);
void dragEnded();
void portalClosed();
void dropped(const QString &uuid, bool accepted);
private slots:
void onDragStarted(const QString &mimeTypes);
void onDragEnded();
void onPortalClosed();
void onDropped(const QString &uuid, bool accepted);
private:
+42 -3
View File
@@ -784,6 +784,7 @@ PortalPanel::PortalPanel(StagingModel *model, QWidget *parent)
if (m_countLabel) {
m_countLabel->setText(tr("%1 项").arg(m_model->count()));
}
updateMode();
refreshLayout();
});
connect(m_model, &StagingModel::countChanged, m_view->viewport(),
@@ -873,7 +874,15 @@ void PortalPanel::setupUi()
connect(m_zone, &PortalZone::portalRequested, this, [this]() {
PortalClient *portal = PortalClient::instance();
if (portal->beginPortal(QRect(mapToGlobal(QPoint(0, 0)), size()))) {
QScreen *scr = screen() ? screen() : QGuiApplication::primaryScreen();
QRect panelRect = geometry();
if (scr) {
const QRect avail = scr->availableGeometry();
panelRect = QRect(avail.x() + avail.width() - width() - m_rightMargin,
avail.y() + avail.height() - height() - m_bottomMargin,
width(), height());
}
if (portal->beginPortal(panelRect)) {
m_zone->setPortalActive(true);
m_zone->showMessage(tr("移动到目标窗口上松手"));
} else {
@@ -886,6 +895,8 @@ void PortalPanel::setupUi()
});
connect(PortalClient::instance(), &PortalClient::dragEnded, this,
[this]() { m_zone->setPortalActive(false); });
connect(PortalClient::instance(), &PortalClient::portalClosed, this,
[this]() { m_zone->setPortalActive(false); });
auto *right = new QVBoxLayout;
right->setContentsMargins(0, 0, 0, 0);
@@ -990,6 +1001,7 @@ void PortalPanel::setupUi()
Q_EMIT askWithContent(text, files);
});
connect(m_factory, &ContentFactory::heightChanged, this, [this]() { refreshLayout(); });
connect(m_factory, &ContentFactory::dragContent, this, &PortalPanel::noteDragContent);
connect(m_factory, &ContentFactory::dragActivity, this, [this]() {
if (m_factoryTimer) {
m_factoryTimer->start();
@@ -1002,6 +1014,32 @@ void PortalPanel::refreshLayout()
updateGeometryForContent();
}
void PortalPanel::setDragging(bool dragging)
{
if (m_dragging == dragging) {
return;
}
m_dragging = dragging;
updateMode();
}
void PortalPanel::updateMode()
{
const bool stagingOnly = !m_dragging && m_model && m_model->count() > 0;
if (stagingOnly == m_stagingOnly) {
return;
}
m_stagingOnly = stagingOnly;
if (m_zone) {
m_zone->setVisible(!stagingOnly);
}
if (m_factory) {
m_factory->setVisible(!stagingOnly);
}
setFixedWidth(stagingOnly ? 360 : kPanelWidth);
refreshLayout();
}
void PortalPanel::updateGeometryForContent()
{
QScreen *scr = screen();
@@ -1020,10 +1058,11 @@ void PortalPanel::updateGeometryForContent()
const int selectionHeight = (m_selectionBar && m_selectionBar->isVisible()) ? 32 : 0;
/* The factory always occupies the same strip, so neither the panel size nor
* its position changes when a drag starts or ends. */
const int factoryHeight = m_factory ? m_factory->sizeHint().height() + 6 : 0;
const int factoryHeight =
(!m_stagingOnly && m_factory) ? m_factory->sizeHint().height() + 6 : 0;
const int totalHeight =
kMargin * 2 + headerHeight + 6 + selectionHeight + listHeight + factoryHeight;
resize(kPanelWidth, totalHeight);
resize(m_stagingOnly ? 360 : kPanelWidth, totalHeight);
}
void PortalPanel::noteDragContent(const QMimeData *mime)
+4
View File
@@ -34,6 +34,7 @@ public:
void refreshLayout();
void popup();
void suppressPortalIfUnderCursor();
void setDragging(bool dragging);
void stopPortalSuppression();
void dismiss();
@@ -52,6 +53,7 @@ private:
void setupUi();
void setupWindow();
void updateGeometryForContent();
void updateMode();
void updateSelectionBar();
void noteDragContent(const QMimeData *mime);
void noteDragFinished();
@@ -79,6 +81,8 @@ private:
int m_bottomMargin = 16;
int m_manualListHeight = 0;
QTimer *m_suppressWatch = nullptr;
bool m_stagingOnly = false;
bool m_dragging = false;
bool m_fixedPosition = true;
bool m_fixedSize = false;
int m_dragMode = 0; // 0 none, 1 move, 2 resize