KiCad PCB EDA Suite
Loading...
Searching...
No Matches
selection.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2013-2017 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 * @author Maciej Suminski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <algorithm>
24#include <eda_item.h>
25#include <tool/selection.h>
26
27
28bool SELECTION::operator==( const SELECTION& aOther ) const
29{
30 return ( m_items == aOther.m_items
31 && m_itemsOrders == aOther.m_itemsOrders
32 && m_isHover == aOther.m_isHover
34 && m_orderCounter == aOther.m_orderCounter );
35}
36
37
39{
40 // We're not sorting here; this is just a time-optimized way to do an
41 // inclusion check. std::lower_bound will return the first i >= aItem
42 // and the second i > aItem check rules out i == aItem.
43 ITER i = std::lower_bound( m_items.begin(), m_items.end(), aItem );
44
45 if( i == m_items.end() || *i > aItem )
46 {
47 m_itemsOrders.insert( m_itemsOrders.begin() + std::distance( m_items.begin(), i ),
49 m_items.insert( i, aItem );
51 m_lastAddedItem = aItem;
52 }
53}
54
55
57{
58 ITER i = std::lower_bound( m_items.begin(), m_items.end(), aItem );
59
60 if( !( i == m_items.end() || *i > aItem ) )
61 {
62 m_itemsOrders.erase( m_itemsOrders.begin() + std::distance( m_items.begin(), i ) );
63 m_items.erase( i );
64
65 if( aItem == m_lastAddedItem )
66 m_lastAddedItem = nullptr;
67 }
68}
69
70
71KIGFX::VIEW_ITEM* SELECTION::GetItem( unsigned int aIdx ) const
72{
73 if( aIdx < m_items.size() )
74 return m_items[aIdx];
75
76 return nullptr;
77}
78
79
80bool SELECTION::Contains( EDA_ITEM* aItem ) const
81{
82 CITER i = std::lower_bound( m_items.begin(), m_items.end(), aItem );
83
84 return !( i == m_items.end() || *i > aItem );
85}
86
87
89{
90 static const std::vector<KICAD_T> textTypes = { SCH_TEXT_T, SCH_LABEL_LOCATE_ANY_T };
91 bool hasOnlyText = true;
92
93 // If the selection contains only texts calculate the center as the mean of all positions
94 // instead of using the center of the total bounding box. Otherwise rotating the selection will
95 // also translate it.
96 for( EDA_ITEM* item : m_items )
97 {
98 if( !item->IsType( textTypes ) )
99 {
100 hasOnlyText = false;
101 break;
102 }
103 }
104
105 BOX2I bbox;
106
107 if( hasOnlyText )
108 {
109 VECTOR2I center( 0, 0 );
110
111 for( EDA_ITEM* item : m_items )
112 center += item->GetPosition();
113
114 center = center / static_cast<int>( m_items.size() );
115 return static_cast<VECTOR2I>( center );
116 }
117
118 for( EDA_ITEM* item : m_items )
119 {
120 if( !item->IsType( { SCH_TEXT_T, SCH_LABEL_LOCATE_ANY_T } ) )
121 bbox.Merge( item->GetBoundingBox() );
122 }
123
124 return static_cast<VECTOR2I>( bbox.GetCenter() );
125}
126
127
129{
130 BOX2I bbox;
131
132 for( EDA_ITEM* item : m_items )
133 bbox.Merge( item->GetBoundingBox() );
134
135 return bbox;
136}
137
138
139bool SELECTION::HasType( KICAD_T aType ) const
140{
141 for( const EDA_ITEM* item : m_items )
142 {
143 if( item->IsType( { aType } ) )
144 return true;
145 }
146
147 return false;
148}
149
150
151size_t SELECTION::CountType( KICAD_T aType ) const
152{
153 size_t count = 0;
154
155 for( const EDA_ITEM* item : m_items )
156 {
157 if( item->IsType( { aType } ) )
158 count++;
159 }
160
161 return count;
162}
163
164
166{
167 if( m_referencePoint )
168 return *m_referencePoint;
169 else
170 return GetBoundingBox().Centre();
171}
172
173
175{
176 m_referencePoint = aP;
177}
178
179
181{
182 m_referencePoint = std::nullopt;
183}
184
185
186const std::vector<KIGFX::VIEW_ITEM*> SELECTION::updateDrawList() const
187{
188 std::vector<VIEW_ITEM*> items;
189
190 for( EDA_ITEM* item : m_items )
191 items.push_back( item );
192
193 return items;
194}
195
196
198{
199 return std::all_of( m_items.begin() + 1, m_items.end(),
200 [&]( const EDA_ITEM* r )
201 {
202 return r->Type() == m_items.front()->Type();
203 } );
204}
205
206
207bool SELECTION::OnlyContains( std::vector<KICAD_T> aList ) const
208{
209 return std::all_of( m_items.begin(), m_items.end(),
210 [&]( const EDA_ITEM* r )
211 {
212 return r->IsType( aList );
213 } );
214}
215
216
217std::vector<EDA_ITEM*> SELECTION::GetItemsSortedByTypeAndXY( bool leftBeforeRight,
218 bool topBeforeBottom ) const
219{
220 std::vector<EDA_ITEM*> sorted_items = std::vector<EDA_ITEM*>( m_items.begin(), m_items.end() );
221
222 std::sort( sorted_items.begin(), sorted_items.end(),
223 [&]( EDA_ITEM* a, EDA_ITEM* b )
224 {
225 if( a->Type() == b->Type() )
226 {
227 const VECTOR2I aPos = a->GetSortPosition();
228 const VECTOR2I bPos = b->GetSortPosition();
229
230 if( aPos.x == bPos.x )
231 {
232 // Ensure deterministic sort
233 if( aPos.y == bPos.y )
234 return a->m_Uuid < b->m_Uuid;
235
236 if( topBeforeBottom )
237 return aPos.y < bPos.y;
238 else
239 return aPos.y > bPos.y;
240 }
241 else if( leftBeforeRight )
242 {
243 return aPos.x < bPos.x;
244 }
245 else
246 {
247 return aPos.x > bPos.x;
248 }
249 }
250 else
251 {
252 return a->Type() < b->Type();
253 }
254 } );
255 return sorted_items;
256}
257
258
259std::vector<EDA_ITEM*> SELECTION::GetItemsSortedBySelectionOrder() const
260{
261 using pairedIterators = std::pair<decltype( m_items.begin() ),
262 decltype( m_itemsOrders.begin() )>;
263
264 // Create a vector of all {selection item, selection order} iterator pairs
265 std::vector<pairedIterators> pairs;
266 auto item = m_items.begin();
267 auto order = m_itemsOrders.begin();
268
269 for( ; item != m_items.end(); ++item, ++order )
270 pairs.emplace_back( make_pair( item, order ) );
271
272 // Sort the pairs by the selection order
273 std::sort( pairs.begin(), pairs.end(),
274 []( pairedIterators const& a, pairedIterators const& b )
275 {
276 return *a.second < *b.second;
277 } );
278
279 // Make a vector of just the sortedItems
280 std::vector<EDA_ITEM*> sortedItems;
281
282 for( pairedIterators sortedItem : pairs )
283 sortedItems.emplace_back( *sortedItem.first );
284
285 return sortedItems;
286}
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr Vec Centre() const
Definition box2.h:93
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr const Vec GetCenter() const
Definition box2.h:226
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
An abstract base class for deriving all objects that can be added to a VIEW.
Definition view_item.h:82
std::deque< EDA_ITEM * > m_items
Definition selection.h:236
virtual void Add(EDA_ITEM *aItem)
Definition selection.cpp:38
int m_orderCounter
Definition selection.h:238
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition selection.cpp:71
bool operator==(const SELECTION &aOther) const
Definition selection.cpp:28
bool m_isHover
Definition selection.h:240
VECTOR2I GetReferencePoint() const
std::deque< int > m_itemsOrders
Definition selection.h:237
std::deque< EDA_ITEM * >::const_iterator CITER
Definition selection.h:73
virtual VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
Definition selection.cpp:88
virtual void Remove(EDA_ITEM *aItem)
Definition selection.cpp:56
bool AreAllItemsIdentical() const
Checks if all items in the selection are the same KICAD_T type.
bool HasType(KICAD_T aType) const
Checks if there is at least one item of requested kind.
std::deque< EDA_ITEM * >::iterator ITER
Definition selection.h:72
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
void ClearReferencePoint()
bool OnlyContains(std::vector< KICAD_T > aList) const
Checks if all items in the selection have a type in aList.
void SetReferencePoint(const VECTOR2I &aP)
EDA_ITEM * m_lastAddedItem
Definition selection.h:239
std::vector< EDA_ITEM * > GetItemsSortedByTypeAndXY(bool leftBeforeRight=true, bool topBeforeBottom=true) const
Returns a copy of this selection of items sorted by their X then Y position.
size_t CountType(KICAD_T aType) const
std::optional< VECTOR2I > m_referencePoint
Definition selection.h:235
bool Contains(EDA_ITEM *aItem) const
Definition selection.cpp:80
virtual BOX2I GetBoundingBox() const
virtual const std::vector< KIGFX::VIEW_ITEM * > updateDrawList() const override
VECTOR2I center
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ SCH_LABEL_LOCATE_ANY_T
Definition typeinfo.h:188
@ SCH_TEXT_T
Definition typeinfo.h:148
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683