parent
6a115f8094
commit
e49123d636
@ -0,0 +1,293 @@
|
||||
Description: Fix DND and drop indicator on desktop
|
||||
(1) When items are dragged and dropped on any desktop position other than
|
||||
that of a directory, they will stick to it (and to its following positions),
|
||||
moving next sticky items if needed. When desktop items are dropped on
|
||||
themselves or on a directory, the DND menu will be shown.
|
||||
.
|
||||
(2) The drop rectangle (when dragging desktop items on desktop folders) is
|
||||
also fixed by drawing it explicitly.
|
||||
Author: Tsu Jan <tsujan2000@gmail.com>
|
||||
Origin: upstream
|
||||
Bug: https://github.com/lxqt/pcmanfm-qt/issues/706, https://github.com/lxqt/pcmanfm-qt/issues/722
|
||||
Applied-Upstream: commit:748a105
|
||||
Last-Update: 2018-07-14
|
||||
--- a/pcmanfm/desktopwindow.cpp
|
||||
+++ b/pcmanfm/desktopwindow.cpp
|
||||
@@ -91,6 +91,7 @@ DesktopWindow::DesktopWindow(int screenN
|
||||
listView_->setMovement(QListView::Snap);
|
||||
listView_->setResizeMode(QListView::Adjust);
|
||||
listView_->setFlow(QListView::TopToBottom);
|
||||
+ listView_->setDropIndicatorShown(false); // we draw the drop indicator ourself
|
||||
|
||||
// This is to workaround Qt bug 54384 which affects Qt >= 5.6
|
||||
// https://bugreports.qt.io/browse/QTBUG-54384
|
||||
@@ -126,7 +127,6 @@ DesktopWindow::DesktopWindow(int screenN
|
||||
connect(proxyModel_, &Fm::ProxyFolderModel::layoutChanged, this, &DesktopWindow::onLayoutChanged);
|
||||
connect(proxyModel_, &Fm::ProxyFolderModel::sortFilterChanged, this, &DesktopWindow::onModelSortFilterChanged);
|
||||
connect(proxyModel_, &Fm::ProxyFolderModel::dataChanged, this, &DesktopWindow::onDataChanged);
|
||||
- connect(listView_, &QListView::indexesMoved, this, &DesktopWindow::onIndexesMoved);
|
||||
}
|
||||
|
||||
// remove frame
|
||||
@@ -710,41 +710,6 @@ void DesktopWindow::onDataChanged(const
|
||||
}
|
||||
}
|
||||
|
||||
-void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) {
|
||||
- auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
- auto itemSize = delegate->itemSize();
|
||||
- // remember the custom position for the items
|
||||
- for(const QModelIndex& index : indexes) {
|
||||
- // Under some circumstances, Qt might emit indexMoved for
|
||||
- // every single cells in the same row. (when QAbstractItemView::SelectItems is set)
|
||||
- // So indexes list may contain several indixes for the same row.
|
||||
- // Since we only care about rows, not individual cells,
|
||||
- // let's handle column 0 of every row here.
|
||||
- if(index.column() == 0) {
|
||||
- auto file = proxyModel_->fileInfoFromIndex(index);
|
||||
- QRect itemRect = listView_->rectForIndex(index);
|
||||
- QPoint tl = itemRect.topLeft();
|
||||
- QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
- workArea.adjust(12, 12, -12, -12);
|
||||
-
|
||||
- // check if the position is occupied by another item
|
||||
- auto existingItem = std::find_if(customItemPos_.cbegin(), customItemPos_.cend(), [tl](const std::pair<std::string, QPoint>& elem){
|
||||
- return elem.second == tl;
|
||||
- });
|
||||
-
|
||||
- if(existingItem == customItemPos_.cend() // don't put items on each other
|
||||
- && tl.x() >= workArea.x() && tl.y() >= workArea.y()
|
||||
- && tl.x() + itemSize.width() <= workArea.right() + 1 // for historical reasons (-> Qt doc)
|
||||
- && tl.y() + itemSize.height() <= workArea.bottom() + 1) { // as above
|
||||
- customItemPos_[file->name()] = tl;
|
||||
- // qDebug() << "indexMoved:" << name << index << itemRect;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- saveItemPositions();
|
||||
- queueRelayout();
|
||||
-}
|
||||
-
|
||||
void DesktopWindow::onFolderStartLoading() { // desktop may be reloaded
|
||||
if(model_) {
|
||||
disconnect(model_, &Fm::FolderModel::filesAdded, this, &DesktopWindow::onFilesAdded);
|
||||
@@ -1247,6 +1212,11 @@ bool DesktopWindow::eventFilter(QObject*
|
||||
}
|
||||
}
|
||||
break;
|
||||
+ case QEvent::Paint:
|
||||
+ // NOTE: The drop indicator isn't drawn/updated automatically, perhaps,
|
||||
+ // because we paint desktop ourself. So, we draw it here.
|
||||
+ paintDropIndicator();
|
||||
+ break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1254,6 +1224,34 @@ bool DesktopWindow::eventFilter(QObject*
|
||||
return Fm::FolderView::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
+void DesktopWindow::childDragMoveEvent(QDragMoveEvent* e) {
|
||||
+ // see DesktopWindow::eventFilter for an explanation
|
||||
+ QRect oldDropRect = dropRect_;
|
||||
+ dropRect_ = QRect();
|
||||
+ QModelIndex index = listView_->indexAt(e->pos());
|
||||
+ if(index.isValid() && index.model()) {
|
||||
+ QVariant data = index.model()->data(index, Fm::FolderModel::Role::FileInfoRole);
|
||||
+ auto info = data.value<std::shared_ptr<const Fm::FileInfo>>();
|
||||
+ if(info && info->isDir()) {
|
||||
+ dropRect_ = listView_->rectForIndex(index);
|
||||
+ }
|
||||
+ }
|
||||
+ if(oldDropRect != dropRect_){
|
||||
+ listView_->viewport()->update();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void DesktopWindow::paintDropIndicator()
|
||||
+{
|
||||
+ if(!dropRect_.isNull()) {
|
||||
+ QPainter painter(listView_->viewport());
|
||||
+ QStyleOption opt;
|
||||
+ opt.init(listView_->viewport());
|
||||
+ opt.rect = dropRect_;
|
||||
+ style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, &painter, listView_);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void DesktopWindow::childDropEvent(QDropEvent* e) {
|
||||
const QMimeData* mimeData = e->mimeData();
|
||||
bool moveItem = false;
|
||||
@@ -1264,45 +1262,59 @@ void DesktopWindow::childDropEvent(QDrop
|
||||
QModelIndex dropIndex = listView_->indexAt(e->pos());
|
||||
if(dropIndex.isValid()) { // drop on an item
|
||||
QModelIndexList selected = selectedIndexes(); // the dragged items
|
||||
- if(selected.contains(dropIndex)) { // drop on self, ignore
|
||||
- moveItem = true;
|
||||
+ if(!selected.contains(dropIndex)) { // not a drop on self
|
||||
+ if(auto file = proxyModel_->fileInfoFromIndex(dropIndex)) {
|
||||
+ if(!file->isDir()) { // drop on a non-directory file
|
||||
+ moveItem = true;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
- else { // drop on a blank area
|
||||
+ else { // drop on a blank area (maybe, between other items)
|
||||
moveItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(moveItem) {
|
||||
e->accept();
|
||||
- }
|
||||
- else {
|
||||
+ // move selected items to the drop position, putting them successively
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
+ QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
+ workArea.adjust(12, 12, -12, -12);
|
||||
+ QPoint pos = mapFromGlobal(e->pos());
|
||||
+ const QModelIndexList indexes = selectedIndexes();
|
||||
+ for(const QModelIndex& indx : indexes) {
|
||||
+ if(auto file = proxyModel_->fileInfoFromIndex(indx)) {
|
||||
+ stickToPosition(QString::fromStdString(file->name()), pos, workArea, grid);
|
||||
+ }
|
||||
+ }
|
||||
+ saveItemPositions();
|
||||
+ queueRelayout();
|
||||
+ }
|
||||
+ else {
|
||||
Fm::FolderView::childDropEvent(e);
|
||||
+ // remove the drop indicator
|
||||
+ dropRect_ = QRect();
|
||||
+ listView_->viewport()->update();
|
||||
// position dropped items successively, starting with the drop rectangle
|
||||
if(mimeData->hasUrls()
|
||||
&& (e->dropAction() == Qt::CopyAction
|
||||
|| e->dropAction() == Qt::MoveAction
|
||||
|| e->dropAction() == Qt::LinkAction)) {
|
||||
- QList<QUrl> urlList = mimeData->urls();
|
||||
- for(int i = 0; i < urlList.count(); ++i) {
|
||||
- std::string name = urlList.at(i).fileName().toUtf8().constData();
|
||||
- if(!name.empty()) { // respect the positions of existing files
|
||||
- QString desktopDir = XdgDir::readDesktopDir() + QString(QLatin1String("/"));
|
||||
- if(!QFile::exists(desktopDir + QString::fromStdString(name))) {
|
||||
- QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
- workArea.adjust(12, 12, -12, -12);
|
||||
- QPoint pos = mapFromGlobal(e->pos());
|
||||
- alignToGrid(pos, workArea.topLeft(), grid, listView_->spacing());
|
||||
- if(i > 0)
|
||||
- pos.setY(pos.y() + grid.height() + listView_->spacing());
|
||||
- if(pos.y() + grid.height() > workArea.bottom() + 1) {
|
||||
- pos.setX(pos.x() + grid.width() + listView_->spacing());
|
||||
- pos.setY(workArea.top());
|
||||
- }
|
||||
- customItemPos_[name] = pos;
|
||||
- }
|
||||
+ auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
+ auto grid = delegate->itemSize();
|
||||
+ QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
+ workArea.adjust(12, 12, -12, -12);
|
||||
+ const QString desktopDir = XdgDir::readDesktopDir() + QString(QLatin1String("/"));
|
||||
+ QPoint pos = mapFromGlobal(e->pos());
|
||||
+ const QList<QUrl> urlList = mimeData->urls();
|
||||
+ for(const QUrl& url : urlList) {
|
||||
+ QString name = url.fileName();
|
||||
+ if(!name.isEmpty()
|
||||
+ // don't stick to the position if there is an overwrite prompt
|
||||
+ && !QFile::exists(desktopDir + name)) {
|
||||
+ stickToPosition(name, pos, workArea, grid);
|
||||
}
|
||||
}
|
||||
saveItemPositions();
|
||||
@@ -1310,10 +1322,39 @@ void DesktopWindow::childDropEvent(QDrop
|
||||
}
|
||||
}
|
||||
|
||||
+// This function recursively repositions next sticky items if needed.
|
||||
+void DesktopWindow::stickToPosition(const QString& file, QPoint& pos, const QRect& workArea, const QSize& grid) {
|
||||
+ // normalize the position
|
||||
+ alignToGrid(pos, workArea.topLeft(), grid, listView_->spacing());
|
||||
+ if(pos.y() + grid.height() > workArea.bottom() + 1) {
|
||||
+ pos.setX(pos.x() + grid.width() + listView_->spacing());
|
||||
+ pos.setY(workArea.top());
|
||||
+ }
|
||||
+ // find if there is a sticky item at this position
|
||||
+ QString otherFile;
|
||||
+ auto oldItem = std::find_if(customItemPos_.cbegin(),
|
||||
+ customItemPos_.cend(),
|
||||
+ [pos](const std::pair<std::string, QPoint>& elem) {
|
||||
+ return elem.second == pos;
|
||||
+ });
|
||||
+ if(oldItem != customItemPos_.cend()) {
|
||||
+ otherFile = QString::fromStdString(oldItem->first);
|
||||
+ }
|
||||
+ // stick to the position
|
||||
+ customItemPos_[file.toStdString()] = pos;
|
||||
+ // find the next position
|
||||
+ pos.setY(pos.y() + grid.height() + listView_->spacing());
|
||||
+ // if there was another sticky item at the same position, move it to the next position
|
||||
+ if(!otherFile.isEmpty() && otherFile != file) {
|
||||
+ QPoint nextPos = pos;
|
||||
+ stickToPosition(otherFile, nextPos, workArea, grid);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void DesktopWindow::alignToGrid(QPoint& pos, const QPoint& topLeft, const QSize& grid, const int spacing) {
|
||||
qreal w = qAbs((qreal)pos.x() - (qreal)topLeft.x())
|
||||
/ (qreal)(grid.width() + spacing);
|
||||
- qreal h = qAbs(pos.y() - (qreal)topLeft.y())
|
||||
+ qreal h = qAbs((qreal)pos.y() - (qreal)topLeft.y())
|
||||
/ (qreal)(grid.height() + spacing);
|
||||
pos.setX(topLeft.x() + qRound(w) * (grid.width() + spacing));
|
||||
pos.setY(topLeft.y() + qRound(h) * (grid.height() + spacing));
|
||||
@@ -1324,7 +1365,7 @@ void DesktopWindow::closeEvent(QCloseEve
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
-void DesktopWindow::paintEvent(QPaintEvent *event) {
|
||||
+void DesktopWindow::paintEvent(QPaintEvent* event) {
|
||||
paintBackground(event);
|
||||
QWidget::paintEvent(event);
|
||||
}
|
||||
--- a/pcmanfm/desktopwindow.h
|
||||
+++ b/pcmanfm/desktopwindow.h
|
||||
@@ -98,9 +98,10 @@ protected:
|
||||
virtual bool event(QEvent* event) override;
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
+ virtual void childDragMoveEvent(QDragMoveEvent* e) override;
|
||||
virtual void childDropEvent(QDropEvent* e) override;
|
||||
virtual void closeEvent(QCloseEvent* event) override;
|
||||
- virtual void paintEvent(QPaintEvent *event) override;
|
||||
+ virtual void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onOpenDirRequested(const Fm::FilePath& path, int target);
|
||||
@@ -112,7 +113,6 @@ protected Q_SLOTS:
|
||||
void onRowsInserted(const QModelIndex& parent, int start, int end);
|
||||
void onLayoutChanged();
|
||||
void onModelSortFilterChanged();
|
||||
- void onIndexesMoved(const QModelIndexList& indexes);
|
||||
void onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
void onFolderStartLoading();
|
||||
void onFolderFinishLoading();
|
||||
@@ -136,6 +136,8 @@ private:
|
||||
void removeBottomGap();
|
||||
void addDesktopActions(QMenu* menu);
|
||||
void paintBackground(QPaintEvent* event);
|
||||
+ void paintDropIndicator();
|
||||
+ void stickToPosition(const QString& file, QPoint& pos, const QRect& workArea, const QSize& grid);
|
||||
static void alignToGrid(QPoint& pos, const QPoint& topLeft, const QSize& grid, const int spacing);
|
||||
|
||||
private:
|
||||
@@ -164,6 +166,8 @@ private:
|
||||
QHash<QModelIndex, QString> displayNames_; // only for desktop entries and shortcuts
|
||||
QTimer* relayoutTimer_;
|
||||
QTimer* selectionTimer_;
|
||||
+
|
||||
+ QRect dropRect_;
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
Description: Always drop into the cell behind cursor
|
||||
Drop desktop items into the cell behind the cursor, regardless of the cursor
|
||||
position inside the cell.
|
||||
.
|
||||
Previously, if the cursor was in the right half of the cell, the item would
|
||||
be dropped into the next cell on the right, and a similar thing happened with
|
||||
the right bottom half.
|
||||
Author: Tsu Jan <tsujan2000@gmail.com>
|
||||
Origin: upstream
|
||||
Bug: https://github.com/lxqt/pcmanfm-qt/issues/728
|
||||
Applied-Upstream: commit:a7898c9
|
||||
Last-Update: 2018-07-14
|
||||
--- a/pcmanfm/desktopwindow.cpp
|
||||
+++ b/pcmanfm/desktopwindow.cpp
|
||||
@@ -59,6 +59,7 @@
|
||||
#include <xcb/xcb.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
+#define WORK_AREA_MARGIN 12 // margin of the work area
|
||||
#define MIN_SLIDE_INTERVAL 5*60000 // 5 min
|
||||
#define MAX_SLIDE_INTERVAL (24*60+55)*60000 // 24 h and 55 min
|
||||
|
||||
@@ -751,7 +752,7 @@ void DesktopWindow::removeBottomGap() {
|
||||
//qDebug() << "delegate:" << delegate->itemSize();
|
||||
QSize cellMargins = getMargins();
|
||||
int workAreaHeight = qApp->desktop()->availableGeometry(screenNum_).height()
|
||||
- - 24; // a 12-pix margin will be considered everywhere
|
||||
+ - 2 * WORK_AREA_MARGIN;
|
||||
int cellHeight = itemSize.height() + listView_->spacing();
|
||||
int iconNumber = workAreaHeight / cellHeight;
|
||||
int bottomGap = workAreaHeight % cellHeight;
|
||||
@@ -827,7 +828,7 @@ void DesktopWindow::relayoutItems() {
|
||||
screen = screenNum_;
|
||||
}
|
||||
QRect workArea = desktop->availableGeometry(screen);
|
||||
- workArea.adjust(12, 12, -12, -12); // add a 12 pixel margin to the work area
|
||||
+ workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
// qDebug() << "workArea" << screen << workArea;
|
||||
// FIXME: we use an internal class declared in a private header here, which is pretty bad.
|
||||
QPoint pos = workArea.topLeft();
|
||||
@@ -902,7 +903,7 @@ void DesktopWindow::loadItemPositions()
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
- workArea.adjust(12, 12, -12, -12);
|
||||
+ workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
QString desktopDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
desktopDir += '/';
|
||||
std::vector<QPoint> usedPos;
|
||||
@@ -1281,8 +1282,8 @@ void DesktopWindow::childDropEvent(QDrop
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
- workArea.adjust(12, 12, -12, -12);
|
||||
- QPoint pos = mapFromGlobal(e->pos());
|
||||
+ workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
+ QPoint pos = e->pos();
|
||||
const QModelIndexList indexes = selectedIndexes();
|
||||
for(const QModelIndex& indx : indexes) {
|
||||
if(auto file = proxyModel_->fileInfoFromIndex(indx)) {
|
||||
@@ -1305,9 +1306,9 @@ void DesktopWindow::childDropEvent(QDrop
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
- workArea.adjust(12, 12, -12, -12);
|
||||
+ workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
const QString desktopDir = XdgDir::readDesktopDir() + QString(QLatin1String("/"));
|
||||
- QPoint pos = mapFromGlobal(e->pos());
|
||||
+ QPoint pos = e->pos();
|
||||
const QList<QUrl> urlList = mimeData->urls();
|
||||
for(const QUrl& url : urlList) {
|
||||
QString name = url.fileName();
|
||||
@@ -1352,12 +1353,10 @@ void DesktopWindow::stickToPosition(cons
|
||||
}
|
||||
|
||||
void DesktopWindow::alignToGrid(QPoint& pos, const QPoint& topLeft, const QSize& grid, const int spacing) {
|
||||
- qreal w = qAbs((qreal)pos.x() - (qreal)topLeft.x())
|
||||
- / (qreal)(grid.width() + spacing);
|
||||
- qreal h = qAbs((qreal)pos.y() - (qreal)topLeft.y())
|
||||
- / (qreal)(grid.height() + spacing);
|
||||
- pos.setX(topLeft.x() + qRound(w) * (grid.width() + spacing));
|
||||
- pos.setY(topLeft.y() + qRound(h) * (grid.height() + spacing));
|
||||
+ int w = qAbs(pos.x() - topLeft.x()) / (grid.width() + spacing);
|
||||
+ int h = qAbs(pos.y() - topLeft.y()) / (grid.height() + spacing);
|
||||
+ pos.setX(topLeft.x() + w * (grid.width() + spacing));
|
||||
+ pos.setY(topLeft.y() + h * (grid.height() + spacing));
|
||||
}
|
||||
|
||||
void DesktopWindow::closeEvent(QCloseEvent* event) {
|
@ -0,0 +1,2 @@
|
||||
polish-dnd-1.patch
|
||||
polish-dnd-2.patch
|
Loading…
Reference in new issue