diff --git a/modules/juce_gui_basics/widgets/juce_ListBox.cpp b/modules/juce_gui_basics/widgets/juce_ListBox.cpp index 96b94eee7b..e8da2c2fb1 100644 --- a/modules/juce_gui_basics/widgets/juce_ListBox.cpp +++ b/modules/juce_gui_basics/widgets/juce_ListBox.cpp @@ -26,15 +26,11 @@ class ListBox::RowComponent : public Component, public TooltipClient { public: - RowComponent (ListBox& lb) - : owner (lb), row (-1), - selected (false), isDragging (false), selectRowOnMouseUp (false) - { - } + RowComponent (ListBox& lb) : owner (lb) {} void paint (Graphics& g) override { - if (ListBoxModel* m = owner.getModel()) + if (auto* m = owner.getModel()) m->paintListBoxItem (row, g, getWidth(), getHeight(), selected); } @@ -47,7 +43,7 @@ public: selected = nowSelected; } - if (ListBoxModel* m = owner.getModel()) + if (auto* m = owner.getModel()) { setMouseCursor (m->getMouseCursorForRow (row)); @@ -61,48 +57,53 @@ public: } } + void performSelection (const MouseEvent& e, bool isMouseUp) + { + owner.selectRowsBasedOnModifierKeys (row, e.mods, isMouseUp); + + if (auto* m = owner.getModel()) + m->listBoxItemClicked (row, e); + } + + bool isInDragToScrollViewport() const noexcept + { + if (auto* vp = owner.getViewport()) + return vp->isScrollOnDragEnabled() && (vp->canScrollVertically() || vp->canScrollHorizontally()); + + return false; + } + void mouseDown (const MouseEvent& e) override { isDragging = false; + isDraggingToScroll = false; selectRowOnMouseUp = false; if (isEnabled()) { - if (owner.selectOnMouseDown && ! selected) - { - owner.selectRowsBasedOnModifierKeys (row, e.mods, false); - - if (ListBoxModel* m = owner.getModel()) - m->listBoxItemClicked (row, e); - } + if (owner.selectOnMouseDown && ! (selected || isInDragToScrollViewport())) + performSelection (e, false); else - { selectRowOnMouseUp = true; - } } } void mouseUp (const MouseEvent& e) override { - if (isEnabled() && selectRowOnMouseUp && ! isDragging) - { - owner.selectRowsBasedOnModifierKeys (row, e.mods, true); - - if (ListBoxModel* m = owner.getModel()) - m->listBoxItemClicked (row, e); - } + if (isEnabled() && selectRowOnMouseUp && ! (isDragging || isDraggingToScroll)) + performSelection (e, true); } void mouseDoubleClick (const MouseEvent& e) override { - if (ListBoxModel* m = owner.getModel()) - if (isEnabled()) + if (isEnabled()) + if (auto* m = owner.getModel()) m->listBoxItemDoubleClicked (row, e); } void mouseDrag (const MouseEvent& e) override { - if (ListBoxModel* m = owner.getModel()) + if (auto* m = owner.getModel()) { if (isEnabled() && e.mouseWasDraggedSinceMouseDown() && ! isDragging) { @@ -115,7 +116,7 @@ public: if (rowsToDrag.size() > 0) { - const var dragDescription (m->getDragSourceDescription (rowsToDrag)); + auto dragDescription = m->getDragSourceDescription (rowsToDrag); if (! (dragDescription.isVoid() || (dragDescription.isString() && dragDescription.toString().isEmpty()))) { @@ -125,6 +126,10 @@ public: } } } + + if (! isDraggingToScroll) + if (auto* vp = owner.getViewport()) + isDraggingToScroll = vp->isCurrentlyScrollingOnDrag(); } void resized() override @@ -135,18 +140,16 @@ public: String getTooltip() override { - if (ListBoxModel* m = owner.getModel()) + if (auto* m = owner.getModel()) return m->getTooltipForRow (row); return {}; } - ScopedPointer customComponent; - -private: ListBox& owner; - int row; - bool selected, isDragging, selectRowOnMouseUp; + ScopedPointer customComponent; + int row = -1; + bool selected = false, isDragging = false, isDraggingToScroll = false, selectRowOnMouseUp = false; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RowComponent) }; @@ -156,12 +159,11 @@ private: class ListBox::ListViewport : public Viewport { public: - ListViewport (ListBox& lb) - : owner (lb) + ListViewport (ListBox& lb) : owner (lb) { setWantsKeyboardFocus (false); - Component* const content = new Component(); + auto content = new Component(); setViewedComponent (content); content->setWantsKeyboardFocus (false); } @@ -193,7 +195,7 @@ public: { updateVisibleArea (true); - if (ListBoxModel* m = owner.getModel()) + if (auto* m = owner.getModel()) m->listWasScrolled(); } @@ -201,11 +203,11 @@ public: { hasUpdated = false; - Component& content = *getViewedComponent(); - const int newX = content.getX(); - int newY = content.getY(); - const int newW = jmax (owner.minimumRowWidth, getMaximumVisibleWidth()); - const int newH = owner.totalItems * owner.getRowHeight(); + auto& content = *getViewedComponent(); + auto newX = content.getX(); + auto newY = content.getY(); + auto newW = jmax (owner.minimumRowWidth, getMaximumVisibleWidth()); + auto newH = owner.totalItems * owner.getRowHeight(); if (newY + newH < getMaximumVisibleHeight() && newH > getMaximumVisibleHeight()) newY = getMaximumVisibleHeight() - newH; @@ -219,20 +221,20 @@ public: void updateContents() { hasUpdated = true; - const int rowH = owner.getRowHeight(); - Component& content = *getViewedComponent(); + auto rowH = owner.getRowHeight(); + auto& content = *getViewedComponent(); if (rowH > 0) { - const int y = getViewPositionY(); - const int w = content.getWidth(); + auto y = getViewPositionY(); + auto w = content.getWidth(); const int numNeeded = 2 + getMaximumVisibleHeight() / rowH; rows.removeRange (numNeeded, rows.size()); while (numNeeded > rows.size()) { - RowComponent* newRow = new RowComponent (owner); + auto newRow = new RowComponent (owner); rows.add (newRow); content.addAndMakeVisible (newRow); } @@ -245,7 +247,7 @@ public: { const int row = i + firstIndex; - if (RowComponent* const rowComp = getComponentForRow (row)) + if (auto* rowComp = getComponentForRow (row)) { rowComp->setBounds (0, row * rowH, w, rowH); rowComp->update (row, owner.isRowSelected (row)); @@ -331,16 +333,15 @@ public: private: ListBox& owner; OwnedArray rows; - int firstIndex, firstWholeIndex, lastWholeIndex; - bool hasUpdated; + int firstIndex = 0, firstWholeIndex = 0, lastWholeIndex = 0; + bool hasUpdated = false; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ListViewport) }; //============================================================================== -class ListBoxMouseMoveSelector : public MouseListener +struct ListBoxMouseMoveSelector : public MouseListener { -public: ListBoxMouseMoveSelector (ListBox& lb) : owner (lb) { owner.addMouseListener (this, true); @@ -353,8 +354,8 @@ public: void mouseMove (const MouseEvent& e) override { - const MouseEvent e2 (e.getEventRelativeTo (&owner)); - owner.selectRow (owner.getRowContainingPosition (e2.x, e2.y), true); + auto pos = e.getEventRelativeTo (&owner).position.toInt(); + owner.selectRow (owner.getRowContainingPosition (pos.x, pos.y), true); } void mouseExit (const MouseEvent& e) override @@ -362,26 +363,14 @@ public: mouseMove (e); } -private: ListBox& owner; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ListBoxMouseMoveSelector) }; //============================================================================== ListBox::ListBox (const String& name, ListBoxModel* const m) - : Component (name), - model (m), - totalItems (0), - rowHeight (22), - minimumRowWidth (0), - outlineThickness (0), - lastRowSelected (-1), - multipleSelection (false), - alwaysFlipSelection (false), - hasDoneInitialUpdate (false), - selectOnMouseDown (true) + : Component (name), model (m) { addAndMakeVisible (viewport = new ListViewport (*this)); @@ -470,7 +459,7 @@ void ListBox::updateContent() if (selected.size() > 0 && selected [selected.size() - 1] >= totalItems) { - selected.removeRange (Range (totalItems, std::numeric_limits::max())); + selected.removeRange ({ totalItems, std::numeric_limits::max() }); lastRowSelected = getSelectedRow (0); selectionChanged = true; } @@ -504,7 +493,7 @@ void ListBox::selectRowInternal (const int row, if (deselectOthersFirst) selected.clear(); - selected.addRange (Range (row, row + 1)); + selected.addRange ({ row, row + 1 }); if (getHeight() == 0 || getWidth() == 0) dontScroll = true; @@ -527,7 +516,7 @@ void ListBox::deselectRow (const int row) { if (selected.contains (row)) { - selected.removeRange (Range (row, row + 1)); + selected.removeRange ({ row, row + 1 }); if (row == lastRowSelected) lastRowSelected = getSelectedRow (0); @@ -541,7 +530,7 @@ void ListBox::setSelectedRows (const SparseSet& setOfRowsToBeSelected, const NotificationType sendNotificationEventToModel) { selected = setOfRowsToBeSelected; - selected.removeRange (Range (totalItems, std::numeric_limits::max())); + selected.removeRange ({ totalItems, std::numeric_limits::max() }); if (! isRowSelected (lastRowSelected)) lastRowSelected = getSelectedRow (0); @@ -565,10 +554,10 @@ void ListBox::selectRangeOfRows (int firstRow, int lastRow, bool dontScrollToSho firstRow = jlimit (0, jmax (0, numRows), firstRow); lastRow = jlimit (0, jmax (0, numRows), lastRow); - selected.addRange (Range (jmin (firstRow, lastRow), - jmax (firstRow, lastRow) + 1)); + selected.addRange ({ jmin (firstRow, lastRow), + jmax (firstRow, lastRow) + 1 }); - selected.removeRange (Range (lastRow, lastRow + 1)); + selected.removeRange ({ lastRow, lastRow + 1 }); } selectRowInternal (lastRow, dontScrollToShowThisRange, false, true); @@ -652,18 +641,15 @@ int ListBox::getRowContainingPosition (const int x, const int y) const noexcept int ListBox::getInsertionIndexForPosition (const int x, const int y) const noexcept { if (isPositiveAndBelow (x, getWidth())) - { - const int row = (viewport->getViewPositionY() + y + rowHeight / 2 - viewport->getY()) / rowHeight; - return jlimit (0, totalItems, row); - } + return jlimit (0, totalItems, (viewport->getViewPositionY() + y + rowHeight / 2 - viewport->getY()) / rowHeight); return -1; } Component* ListBox::getComponentForRowNumber (const int row) const noexcept { - if (RowComponent* const listRowComp = viewport->getComponentForRowIfOnscreen (row)) - return static_cast (listRowComp->customComponent); + if (auto* listRowComp = viewport->getComponentForRowIfOnscreen (row)) + return listRowComp->customComponent; return nullptr; } @@ -673,21 +659,20 @@ int ListBox::getRowNumberOfComponent (Component* const rowComponent) const noexc return viewport->getRowNumberOfComponent (rowComponent); } -Rectangle ListBox::getRowPosition (const int rowNumber, - const bool relativeToComponentTopLeft) const noexcept +Rectangle ListBox::getRowPosition (int rowNumber, bool relativeToComponentTopLeft) const noexcept { - int y = viewport->getY() + rowHeight * rowNumber; + auto y = viewport->getY() + rowHeight * rowNumber; if (relativeToComponentTopLeft) y -= viewport->getViewPositionY(); - return Rectangle (viewport->getX(), y, - viewport->getViewedComponent()->getWidth(), rowHeight); + return { viewport->getX(), y, + viewport->getViewedComponent()->getWidth(), rowHeight }; } void ListBox::setVerticalPosition (const double proportion) { - const int offscreen = viewport->getViewedComponent()->getHeight() - viewport->getHeight(); + auto offscreen = viewport->getViewedComponent()->getHeight() - viewport->getHeight(); viewport->setViewPosition (viewport->getViewPositionX(), jmax (0, roundToInt (proportion * offscreen))); @@ -695,10 +680,10 @@ void ListBox::setVerticalPosition (const double proportion) double ListBox::getVerticalPosition() const { - const int offscreen = viewport->getViewedComponent()->getHeight() - viewport->getHeight(); + auto offscreen = viewport->getViewedComponent()->getHeight() - viewport->getHeight(); - return (offscreen > 0) ? viewport->getViewPositionY() / (double) offscreen - : 0; + return offscreen > 0 ? viewport->getViewPositionY() / (double) offscreen + : 0; } int ListBox::getVisibleRowWidth() const noexcept @@ -842,20 +827,10 @@ void ListBox::setMinimumContentWidth (const int newMinimumWidth) updateContent(); } -int ListBox::getVisibleContentWidth() const noexcept -{ - return viewport->getMaximumVisibleWidth(); -} +int ListBox::getVisibleContentWidth() const noexcept { return viewport->getMaximumVisibleWidth(); } -ScrollBar* ListBox::getVerticalScrollBar() const noexcept -{ - return viewport->getVerticalScrollBar(); -} - -ScrollBar* ListBox::getHorizontalScrollBar() const noexcept -{ - return viewport->getHorizontalScrollBar(); -} +ScrollBar* ListBox::getVerticalScrollBar() const noexcept { return viewport->getVerticalScrollBar(); } +ScrollBar* ListBox::getHorizontalScrollBar() const noexcept { return viewport->getHorizontalScrollBar(); } void ListBox::colourChanged() { @@ -894,39 +869,42 @@ void ListBox::repaintRow (const int rowNumber) noexcept Image ListBox::createSnapshotOfRows (const SparseSet& rows, int& imageX, int& imageY) { Rectangle imageArea; - const int firstRow = getRowContainingPosition (0, viewport->getY()); + auto firstRow = getRowContainingPosition (0, viewport->getY()); for (int i = getNumRowsOnScreen() + 2; --i >= 0;) { - Component* rowComp = viewport->getComponentForRowIfOnscreen (firstRow + i); - - if (rowComp != nullptr && rows.contains (firstRow + i)) + if (rows.contains (firstRow + i)) { - const Point pos (getLocalPoint (rowComp, Point())); - const Rectangle rowRect (pos.getX(), pos.getY(), rowComp->getWidth(), rowComp->getHeight()); - imageArea = imageArea.getUnion (rowRect); + if (auto* rowComp = viewport->getComponentForRowIfOnscreen (firstRow + i)) + { + auto pos = getLocalPoint (rowComp, Point()); + + imageArea = imageArea.getUnion ({ pos.x, pos.y, rowComp->getWidth(), rowComp->getHeight() }); + } } } imageArea = imageArea.getIntersection (getLocalBounds()); imageX = imageArea.getX(); imageY = imageArea.getY(); + Image snapshot (Image::ARGB, imageArea.getWidth(), imageArea.getHeight(), true); for (int i = getNumRowsOnScreen() + 2; --i >= 0;) { - Component* rowComp = viewport->getComponentForRowIfOnscreen (firstRow + i); - - if (rowComp != nullptr && rows.contains (firstRow + i)) + if (rows.contains (firstRow + i)) { - Graphics g (snapshot); - g.setOrigin (getLocalPoint (rowComp, Point()) - imageArea.getPosition()); - - if (g.reduceClipRegion (rowComp->getLocalBounds())) + if (auto* rowComp = viewport->getComponentForRowIfOnscreen (firstRow + i)) { - g.beginTransparencyLayer (0.6f); - rowComp->paintEntireComponent (g, false); - g.endTransparencyLayer(); + Graphics g (snapshot); + g.setOrigin (getLocalPoint (rowComp, Point()) - imageArea.getPosition()); + + if (g.reduceClipRegion (rowComp->getLocalBounds())) + { + g.beginTransparencyLayer (0.6f); + rowComp->paintEntireComponent (g, false); + g.endTransparencyLayer(); + } } } } @@ -936,13 +914,12 @@ Image ListBox::createSnapshotOfRows (const SparseSet& rows, int& imageX, in void ListBox::startDragAndDrop (const MouseEvent& e, const SparseSet& rowsToDrag, const var& dragDescription, bool allowDraggingToOtherWindows) { - if (DragAndDropContainer* const dragContainer = DragAndDropContainer::findParentDragContainerFor (this)) + if (auto* dragContainer = DragAndDropContainer::findParentDragContainerFor (this)) { int x, y; - Image dragImage = createSnapshotOfRows (rowsToDrag, x, y); + auto dragImage = createSnapshotOfRows (rowsToDrag, x, y); - MouseEvent e2 (e.getEventRelativeTo (this)); - const Point p (x - e2.x, y - e2.y); + auto p = Point (x, y) - e.getEventRelativeTo (this).position.toInt(); dragContainer->startDragging (dragDescription, this, dragImage, allowDraggingToOtherWindows, &p); } else diff --git a/modules/juce_gui_basics/widgets/juce_ListBox.h b/modules/juce_gui_basics/widgets/juce_ListBox.h index 2bec6938bd..d4fc1197ca 100644 --- a/modules/juce_gui_basics/widgets/juce_ListBox.h +++ b/modules/juce_gui_basics/widgets/juce_ListBox.h @@ -577,11 +577,11 @@ private: ScopedPointer viewport; ScopedPointer headerComponent; ScopedPointer mouseMoveSelector; - int totalItems, rowHeight, minimumRowWidth; - int outlineThickness; - int lastRowSelected; - bool multipleSelection, alwaysFlipSelection, hasDoneInitialUpdate, selectOnMouseDown; SparseSet selected; + int totalItems = 0, rowHeight = 22, minimumRowWidth = 0; + int outlineThickness = 0; + int lastRowSelected = -1; + bool multipleSelection = false, alwaysFlipSelection = false, hasDoneInitialUpdate = false, selectOnMouseDown = true; void selectRowInternal (int rowNumber, bool dontScrollToShowThisRow, bool deselectOthersFirst, bool isMouseClick);