From 18010b1104aa246a0459abfc67f3a492a1c4eb50 Mon Sep 17 00:00:00 2001
From: Mike Williams <mike@mikebwilliams.com>
Date: Wed, 19 Mar 2025 10:25:35 -0400
Subject: [PATCH] selection: sort box selection by rows and columns by default

Some tools can take a selection order and it is nice to provide a
sane human-oriented default sorting when box selecting.
---
 eeschema/tools/sch_selection_tool.cpp | 18 +++++++++++++++++-
 pcbnew/tools/pcb_selection_tool.cpp   | 14 ++++++++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/eeschema/tools/sch_selection_tool.cpp b/eeschema/tools/sch_selection_tool.cpp
index c517be750f..b86386756f 100644
--- a/eeschema/tools/sch_selection_tool.cpp
+++ b/eeschema/tools/sch_selection_tool.cpp
@@ -1976,6 +1976,22 @@ bool SCH_SELECTION_TOOL::selectMultiple()
                 }
             }
 
+            std::vector<EDA_ITEM*> sortedNearbyItems( nearbyItems.begin(), nearbyItems.end() );
+
+            // Sort the filtered selection by rows and columns to have a nice default
+            // for tools that can use it.
+            std::sort( sortedNearbyItems.begin(), sortedNearbyItems.end(),
+                       []( EDA_ITEM* a, EDA_ITEM* b )
+                       {
+                           VECTOR2I aPos = a->GetPosition();
+                           VECTOR2I bPos = b->GetPosition();
+
+                           if( aPos.y == bPos.y )
+                               return aPos.x < bPos.x;
+
+                           return aPos.y < bPos.y;
+                       } );
+
             BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
             selectionRect.Normalize();
 
@@ -2011,7 +2027,7 @@ bool SCH_SELECTION_TOOL::selectMultiple()
                         }
                     };
 
-            for( EDA_ITEM* item : nearbyItems )
+            for( EDA_ITEM* item : sortedNearbyItems )
             {
                 bool           selected = false;
                 EDA_ITEM_FLAGS flags    = 0;
diff --git a/pcbnew/tools/pcb_selection_tool.cpp b/pcbnew/tools/pcb_selection_tool.cpp
index cee1feaa55..e11d7d2849 100644
--- a/pcbnew/tools/pcb_selection_tool.cpp
+++ b/pcbnew/tools/pcb_selection_tool.cpp
@@ -1189,6 +1189,20 @@ bool PCB_SELECTION_TOOL::selectMultiple()
                 FilterCollectorForHierarchy( collector, true );
             }
 
+            // Sort the filtered selection by rows and columns to have a nice default
+            // for tools that can use it.
+            std::sort( collector.begin(), collector.end(),
+                       []( EDA_ITEM* a, EDA_ITEM* b )
+                       {
+                           VECTOR2I aPos = a->GetPosition();
+                           VECTOR2I bPos = b->GetPosition();
+
+                           if( aPos.y == bPos.y )
+                               return aPos.x < bPos.x;
+
+                           return aPos.y < bPos.y;
+                       } );
+
             for( EDA_ITEM* i : collector )
             {
                 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );