newHoveredWidget->setExpansionAreaHovered(true);
} else {
// make sure we unhover the old one first if old!=new
- if (auto oldHoveredWidget = hoveredWidget(); oldHoveredWidget && oldHoveredWidget != newHoveredWidget) {
+ auto oldHoveredWidget = hoveredWidget();
+ if (oldHoveredWidget && oldHoveredWidget != newHoveredWidget) {
oldHoveredWidget->setHovered(false);
Q_EMIT itemUnhovered(oldHoveredWidget->index());
}
// (no-op in this branch for masked hover)
} else {
- newHoveredWidget->setHovered(true);
newHoveredWidget->setHoverPosition(mappedPos);
- Q_EMIT itemHovered(newHoveredWidget->index());
+ if (oldHoveredWidget != newHoveredWidget) {
+ newHoveredWidget->setHovered(true);
+ Q_EMIT itemHovered(newHoveredWidget->index());
+ }
}
}
} else {
const bool shiftPressed = modifiers & Qt::ShiftModifier;
const bool controlPressed = modifiers & Qt::ControlModifier;
+ const bool leftClick = buttons & Qt::LeftButton;
const bool rightClick = buttons & Qt::RightButton;
// The previous selection is cleared if either
}
if (m_pressedIndex.has_value()) {
+ // The hover highlight area of an item is being pressed.
m_selectionManager->setCurrentItem(m_pressedIndex.value());
const auto row = m_view->m_visibleItems.value(m_pressedIndex.value()); // anything outside of row.contains() will be the empty region of the row rect
const bool hitTargetIsRowEmptyRegion = !row->contains(row->mapFromItem(m_view, pos));
bool createRubberBand = (hitTargetIsRowEmptyRegion && m_selectionManager->selectedItems().isEmpty());
if (rightClick && hitTargetIsRowEmptyRegion) {
- // we got a right click outside the text rect, default to action on the current url and not the pressed item
- Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
+ // We have a right click outside the icon and text rect but within the hover highlight area
+ // but it is unclear if this means that a selection rectangle for an item was clicked or the background of the view.
+ if (m_selectionManager->selectedItems().contains(m_pressedIndex.value())) {
+ // The selection rectangle for an item was clicked
+ Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
+ } else {
+ Q_EMIT viewContextMenuRequested(screenPos);
+ }
return true;
}
break;
case MultiSelection:
- if (controlPressed && !shiftPressed) {
- m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
- m_selectionManager->beginAnchoredSelection(m_pressedIndex.value());
- createRubberBand = false; // multi selection, don't propagate any further
+ if (controlPressed && !shiftPressed && leftClick) {
+ // A left mouse button press is happening on an item while control is pressed. This either means a user wants to:
+ // - toggle the selection of item(s) or
+ // - they want to begin a drag on the item(s) to copy them.
+ // We rule out the latter, if the item is not clicked directly and was unselected previously.
+ const auto row = m_view->m_visibleItems.value(m_pressedIndex.value());
+ const auto mappedPos = row->mapFromItem(m_view, pos);
+ if (!row->iconRect().contains(mappedPos) && !row->textRect().contains(mappedPos) && !pressedItemAlreadySelected) {
+ createRubberBand = true;
+ } else {
+ m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
+ m_selectionManager->beginAnchoredSelection(m_pressedIndex.value());
+ createRubberBand = false; // multi selection, don't propagate any further
+ // This will be the start of an item drag-to-copy operation if the user now moves the mouse before releasing the mouse button.
+ }
} else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) {
// Select the pressed item and start a new anchored selection
m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Select);