Merge ~kristoffer-odmark/kicad:tom-copypasta into ~kicad-product-committers/kicad:master
- Git
- lp:~kristoffer-odmark/kicad
- tom-copypasta
- Merge into master
Status: | Merged |
---|---|
Merged at revision: | 4a5d400ec26d8805935da3663293528be0fd9a06 |
Proposed branch: | ~kristoffer-odmark/kicad:tom-copypasta |
Merge into: | ~kicad-product-committers/kicad:master |
Diff against target: |
1779 lines (+987/-155) 20 files modified
common/CMakeLists.txt (+1/-0) include/tool/selection.h (+23/-0) pcbnew/board_commit.cpp (+1/-0) pcbnew/kicad_clipboard.cpp (+311/-0) pcbnew/kicad_clipboard.h (+81/-0) pcbnew/kicad_plugin.cpp (+111/-5) pcbnew/kicad_plugin.h (+16/-1) pcbnew/pcb_parser.h (+8/-8) pcbnew/tools/edit_tool.cpp (+101/-13) pcbnew/tools/edit_tool.h (+24/-1) pcbnew/tools/grid_helper.cpp (+7/-1) pcbnew/tools/module_editor_tools.cpp (+4/-17) pcbnew/tools/pcb_actions.h (+10/-0) pcbnew/tools/pcb_editor_control.cpp (+12/-2) pcbnew/tools/pcb_tool.h (+2/-0) pcbnew/tools/pcbnew_control.cpp (+245/-95) pcbnew/tools/pcbnew_control.h (+12/-4) pcbnew/tools/picker_tool.cpp (+11/-2) pcbnew/tools/picker_tool.h (+3/-4) pcbnew/tools/selection_tool.cpp (+4/-2) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tomasz Wlostowski | Pending | ||
Review via email: mp+331369@code.launchpad.net |
Commit message
Description of the change
Added copy-paste functionality to pcbnew. Coworked with Tomasz. I think it is fully acceptable in the current state and ready for mainstream testing.
Wayne Stambaugh (stambaughw) wrote : | # |
- 1faee98... by Kristoffer
-
some coding violations fixed
Kristoffer (kristoffer-odmark) wrote : | # |
Does it look better now?
Tomasz Wlostowski (twlostow) wrote : | # |
On 27.09.2017 20:46, Kristoffer wrote:
> Does it look better now?
>
Hi Kristoffer,
I've had a quick look (not at the code style yet):
- there's a bug that makes the selection go in crazy direciton when
moving cursor with arrow keys. I'm working now to fix it.
- the code for merging NETINFO_ITEMs from the board being pasted is OK,
but the net propagation is not what I meant (in some cases, pasted
tracks/vias don't inherit the nets of the pads they're pasted over).
Tom
Kristoffer (kristoffer-odmark) wrote : | # |
Any progress?
Franck78 (fbourdonnec) wrote : | # |
Why is this thing still in 'pending' state ????????????????
It ages around 4.0.7 release (2017)
We are 2 years latter 5.1.x (2019)
Some Copy/paste in v5 v6 is implemented
Except for discouraging a new developer (too late for Kristoffer) to join, a patch is accepted or rejected in a reasonable delay.
Tomasz Wlostowski (twlostow) wrote : | # |
The branch was merged in 2017, with the exception of two last commits (https:/
And since you mentioned discouraging developers - stop bitching, Franck. You are not contributing anything valuable to the project, just complaining. I sometimes feel quite discouraged from contributing just because of your negativity.
Tom
Preview Diff
1 | diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt |
2 | index a325d23..93d4692 100644 |
3 | --- a/common/CMakeLists.txt |
4 | +++ b/common/CMakeLists.txt |
5 | @@ -403,6 +403,7 @@ set( PCB_COMMON_SRCS |
6 | ../pcbnew/eagle_plugin.cpp |
7 | ../pcbnew/legacy_plugin.cpp |
8 | ../pcbnew/kicad_plugin.cpp |
9 | + ../pcbnew/kicad_clipboard.cpp |
10 | ../pcbnew/gpcb_plugin.cpp |
11 | ../pcbnew/pcb_netlist.cpp |
12 | widgets/widget_net_selector.cpp |
13 | diff --git a/include/tool/selection.h b/include/tool/selection.h |
14 | index 7e4f488..fb0c735 100644 |
15 | --- a/include/tool/selection.h |
16 | +++ b/include/tool/selection.h |
17 | @@ -170,7 +170,30 @@ public: |
18 | |
19 | virtual const VIEW_GROUP::ITEMS updateDrawList() const override; |
20 | |
21 | + bool HasReferencePoint() const |
22 | + { |
23 | + return m_referencePoint != boost::none; |
24 | + } |
25 | + |
26 | + VECTOR2I GetReferencePoint() const |
27 | + { |
28 | + return *m_referencePoint; |
29 | + } |
30 | + |
31 | + void SetReferencePoint( const VECTOR2I& aP ) |
32 | + { |
33 | + m_referencePoint = aP; |
34 | + } |
35 | + |
36 | + void ClearReferencePoint() |
37 | + { |
38 | + m_referencePoint = boost::none; |
39 | + } |
40 | + |
41 | private: |
42 | + |
43 | + boost::optional<VECTOR2I> m_referencePoint; |
44 | + |
45 | /// Set of selected items |
46 | std::set<EDA_ITEM*> m_items; |
47 | |
48 | diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp |
49 | index 8ddfbcb..a967096 100644 |
50 | --- a/pcbnew/board_commit.cpp |
51 | +++ b/pcbnew/board_commit.cpp |
52 | @@ -132,6 +132,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry ) |
53 | // modules inside modules are not supported yet |
54 | assert( boardItem->Type() != PCB_MODULE_T ); |
55 | |
56 | + boardItem->SetParent( board->m_Modules.GetFirst() ); |
57 | if( !( changeFlags & CHT_DONE ) ) |
58 | board->m_Modules->Add( boardItem ); |
59 | } |
60 | diff --git a/pcbnew/kicad_clipboard.cpp b/pcbnew/kicad_clipboard.cpp |
61 | new file mode 100644 |
62 | index 0000000..38b59cf |
63 | --- /dev/null |
64 | +++ b/pcbnew/kicad_clipboard.cpp |
65 | @@ -0,0 +1,311 @@ |
66 | +/* |
67 | + * This program source code file is part of KiCad, a free EDA CAD application. |
68 | + * |
69 | + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. |
70 | + * @author Kristoffer Ödmark |
71 | + * |
72 | + * This program is free software; you can redistribute it and/or |
73 | + * modify it under the terms of the GNU General Public License |
74 | + * as published by the Free Software Foundation; either version 2 |
75 | + * of the License, or (at your option) any later version. |
76 | + * |
77 | + * This program is distributed in the hope that it will be useful, |
78 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
79 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
80 | + * GNU General Public License for more details. |
81 | + * |
82 | + * You should have received a copy of the GNU General Public License |
83 | + * along with this program; if not, you may find one here: |
84 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
85 | + * or you may search the http://www.gnu.org website for the version 2 license, |
86 | + * or you may write to the Free Software Foundation, Inc., |
87 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
88 | + */ |
89 | + |
90 | +#include <wx/clipbrd.h> |
91 | +#include <common.h> |
92 | +#include <pcb_parser.h> |
93 | +#include <class_netinfo.h> |
94 | +#include <class_board.h> |
95 | +#include <build_version.h> |
96 | + |
97 | +#include <kicad_plugin.h> |
98 | +#include <kicad_clipboard.h> |
99 | + |
100 | +CLIPBOARD_IO::CLIPBOARD_IO(): |
101 | + PCB_IO( CTL_STD_LAYER_NAMES ), |
102 | + m_formatter(), |
103 | + m_parser( new CLIPBOARD_PARSER() ) |
104 | +{ |
105 | + m_out = &m_formatter; |
106 | +} |
107 | + |
108 | + |
109 | +CLIPBOARD_IO::~CLIPBOARD_IO(){} |
110 | + |
111 | + |
112 | +STRING_FORMATTER* CLIPBOARD_IO::GetFormatter() |
113 | +{ |
114 | + return &m_formatter; |
115 | +} |
116 | + |
117 | + |
118 | +void CLIPBOARD_IO::SetBoard( BOARD* aBoard ) |
119 | +{ |
120 | + m_board = aBoard; |
121 | +} |
122 | + |
123 | + |
124 | +void CLIPBOARD_IO::SaveSelection( const SELECTION& aSelected ) |
125 | +{ |
126 | + LOCALE_IO toggle; // toggles on, then off, the C locale. |
127 | + VECTOR2I refPoint( 0, 0 ); |
128 | + |
129 | + // dont even start if the selection is empty |
130 | + if( aSelected.Empty() ) |
131 | + return; |
132 | + |
133 | + if( aSelected.HasReferencePoint() ) |
134 | + refPoint = aSelected.GetReferencePoint(); |
135 | + |
136 | + // Prepare net mapping that assures that net codes saved in a file are consecutive integers |
137 | + m_mapping->SetBoard( m_board ); |
138 | + |
139 | + // Differentiate how it is formatted depending on what selection contains |
140 | + bool onlyModuleParts = true; |
141 | + for( const auto i : aSelected ) |
142 | + { |
143 | + // check if it not one of the module primitives |
144 | + if( ( i->Type() != PCB_MODULE_EDGE_T ) && |
145 | + ( i->Type() != PCB_MODULE_TEXT_T ) && |
146 | + ( i->Type() != PCB_PAD_T ) ) |
147 | + { |
148 | + onlyModuleParts = false; |
149 | + continue; |
150 | + } |
151 | + } |
152 | + |
153 | + // if there is only parts of a module selected, format it as a new module else |
154 | + // format it as an entire board |
155 | + MODULE partialModule( m_board ); |
156 | + |
157 | + // only a module selected. |
158 | + if( aSelected.Size() == 1 && aSelected.Front()->Type() == PCB_MODULE_T ) |
159 | + { |
160 | + // make the module safe to transfer to other pcbs |
161 | + const MODULE* mod = static_cast<MODULE*>( aSelected.Front() ); |
162 | + // Do not modify existing board |
163 | + MODULE newModule(*mod); |
164 | + |
165 | + for( D_PAD* pad = newModule.PadsList().begin(); pad; pad = pad->Next() ) |
166 | + { |
167 | + pad->SetNetCode( 0, 0 ); |
168 | + } |
169 | + |
170 | + // locate the reference point at (0, 0) in the copied items |
171 | + newModule.Move( wxPoint( -refPoint.x, -refPoint.y ) ); |
172 | + |
173 | + Format( static_cast<BOARD_ITEM*>( &newModule ) ); |
174 | + } |
175 | + // partial module selected. |
176 | + else if( onlyModuleParts ) |
177 | + { |
178 | + for( const auto item : aSelected ) |
179 | + { |
180 | + auto clone = static_cast<BOARD_ITEM*>( item->Clone() ); |
181 | + |
182 | + // Do not add reference/value - convert them to the common type |
183 | + if( TEXTE_MODULE* text = dyn_cast<TEXTE_MODULE*>( clone ) ) |
184 | + text->SetType( TEXTE_MODULE::TEXT_is_DIVERS ); |
185 | + |
186 | + // If it is only a module, clear the nets from the pads |
187 | + if( clone->Type() == PCB_PAD_T ) |
188 | + { |
189 | + D_PAD* pad = static_cast<D_PAD*>( clone ); |
190 | + pad->SetNetCode( 0, 0 ); |
191 | + } |
192 | + |
193 | + // locate the reference point at (0, 0) in the copied items |
194 | + clone->Move( wxPoint(-refPoint.x, -refPoint.y ) ); |
195 | + |
196 | + partialModule.Add( clone ); |
197 | + } |
198 | + |
199 | + // Set the new relative internal local coordinates of copied items |
200 | + MODULE* editedModule = m_board->m_Modules; |
201 | + wxPoint moveVector = partialModule.GetPosition() + editedModule->GetPosition(); |
202 | + |
203 | + partialModule.MoveAnchorPosition( moveVector ); |
204 | + |
205 | + Format( &partialModule, 0 ); |
206 | + |
207 | + } |
208 | + // lots of stuff selected |
209 | + else |
210 | + { |
211 | + // we will fake being a .kicad_pcb to get the full parser kicking |
212 | + // This means we also need layers and nets |
213 | + m_formatter.Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", |
214 | + SEXPR_BOARD_FILE_VERSION, m_formatter.Quotew( GetBuildVersion() ).c_str() ); |
215 | + |
216 | + |
217 | + m_formatter.Print( 0, "\n" ); |
218 | + |
219 | + formatBoardLayers( m_board ); |
220 | + formatNetInformation( m_board ); |
221 | + |
222 | + m_formatter.Print( 0, "\n" ); |
223 | + |
224 | + |
225 | + for( const auto i : aSelected ) |
226 | + { |
227 | + // Dont format stuff that cannot exist standalone! |
228 | + if( ( i->Type() != PCB_MODULE_EDGE_T ) && |
229 | + ( i->Type() != PCB_MODULE_TEXT_T ) && |
230 | + ( i->Type() != PCB_PAD_T ) ) |
231 | + { |
232 | + auto item = static_cast<BOARD_ITEM*>( i ); |
233 | + std::unique_ptr<BOARD_ITEM> clone( static_cast<BOARD_ITEM*> ( item->Clone() ) ); |
234 | + |
235 | + // locate the reference point at (0, 0) in the copied items |
236 | + clone->Move( wxPoint(-refPoint.x, -refPoint.y ) ); |
237 | + |
238 | + Format( clone.get(), 1 ); |
239 | + } |
240 | + |
241 | + } |
242 | + m_formatter.Print( 0, "\n)" ); |
243 | + } |
244 | + if( wxTheClipboard->Open() ) |
245 | + { |
246 | + wxTheClipboard->SetData( new wxTextDataObject( |
247 | + wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) ); |
248 | + wxTheClipboard->Close(); |
249 | + } |
250 | +} |
251 | + |
252 | + |
253 | +BOARD_ITEM* CLIPBOARD_IO::Parse() |
254 | +{ |
255 | + std::string result; |
256 | + |
257 | + if( wxTheClipboard->Open() ) |
258 | + { |
259 | + if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) |
260 | + { |
261 | + wxTextDataObject data; |
262 | + wxTheClipboard->GetData( data ); |
263 | + |
264 | + result = data.GetText().mb_str(); |
265 | + } |
266 | + |
267 | + wxTheClipboard->Close(); |
268 | + } |
269 | + |
270 | + BOARD_ITEM *item; |
271 | + try |
272 | + { |
273 | + item = PCB_IO::Parse( result ); |
274 | + } catch (...) { |
275 | + item = nullptr; |
276 | + } |
277 | + |
278 | + return item; |
279 | +} |
280 | + |
281 | + |
282 | +void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard, |
283 | + const PROPERTIES* aProperties ) |
284 | +{ |
285 | + LOCALE_IO toggle; // toggles on, then off, the C locale. |
286 | + |
287 | + init( aProperties ); |
288 | + |
289 | + m_board = aBoard; // after init() |
290 | + |
291 | + // Prepare net mapping that assures that net codes saved in a file are consecutive integers |
292 | + m_mapping->SetBoard( aBoard ); |
293 | + |
294 | + STRING_FORMATTER formatter; |
295 | + |
296 | + m_out = &formatter; |
297 | + |
298 | + m_out->Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION, |
299 | + formatter.Quotew( GetBuildVersion() ).c_str() ); |
300 | + |
301 | + Format( aBoard, 1 ); |
302 | + |
303 | + m_out->Print( 0, ")\n" ); |
304 | + |
305 | + if( wxTheClipboard->Open() ) |
306 | + { |
307 | + wxTheClipboard->SetData( new wxTextDataObject( |
308 | + wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) ); |
309 | + wxTheClipboard->Close(); |
310 | + } |
311 | + |
312 | +} |
313 | + |
314 | + |
315 | +BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, |
316 | + BOARD* aAppendToMe, const PROPERTIES* aProperties ) |
317 | +{ |
318 | + std::string result; |
319 | + |
320 | + if( wxTheClipboard->Open() ) |
321 | + { |
322 | + if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) |
323 | + { |
324 | + wxTextDataObject data; |
325 | + wxTheClipboard->GetData( data ); |
326 | + |
327 | + result = data.GetText().mb_str(); |
328 | + } |
329 | + |
330 | + wxTheClipboard->Close(); |
331 | + } |
332 | + |
333 | + STRING_LINE_READER reader(result, wxT( "clipboard" ) ); |
334 | + |
335 | + init( aProperties ); |
336 | + |
337 | + m_parser->SetLineReader( &reader ); |
338 | + m_parser->SetBoard( aAppendToMe ); |
339 | + |
340 | + BOARD_ITEM* item; |
341 | + BOARD* board; |
342 | + |
343 | + try |
344 | + { |
345 | + item = m_parser->Parse(); |
346 | + } |
347 | + catch( const FUTURE_FORMAT_ERROR& ) |
348 | + { |
349 | + // Don't wrap a FUTURE_FORMAT_ERROR in another |
350 | + throw; |
351 | + } |
352 | + catch( const PARSE_ERROR& parse_error ) |
353 | + { |
354 | + if( m_parser->IsTooRecent() ) |
355 | + throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() ); |
356 | + else |
357 | + throw; |
358 | + } |
359 | + |
360 | + if( item->Type() != PCB_T ) |
361 | + { |
362 | + // The parser loaded something that was valid, but wasn't a board. |
363 | + THROW_PARSE_ERROR( _( "Clipboard content is not Kicad compatible" ), |
364 | + m_parser->CurSource(), m_parser->CurLine(), |
365 | + m_parser->CurLineNumber(), m_parser->CurOffset() ); |
366 | + } |
367 | + else |
368 | + { |
369 | + board = dynamic_cast<BOARD*>( item ); |
370 | + } |
371 | + // Give the filename to the board if it's new |
372 | + if( !aAppendToMe ) |
373 | + board->SetFileName( aFileName ); |
374 | + |
375 | + return board; |
376 | +} |
377 | diff --git a/pcbnew/kicad_clipboard.h b/pcbnew/kicad_clipboard.h |
378 | new file mode 100644 |
379 | index 0000000..ccc2877 |
380 | --- /dev/null |
381 | +++ b/pcbnew/kicad_clipboard.h |
382 | @@ -0,0 +1,81 @@ |
383 | +/* |
384 | + * This program source code file is part of KiCad, a free EDA CAD application. |
385 | + * |
386 | + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. |
387 | + * @author Kristoffer Ödmark |
388 | + * |
389 | + * This program is free software; you can redistribute it and/or |
390 | + * modify it under the terms of the GNU General Public License |
391 | + * as published by the Free Software Foundation; either version 2 |
392 | + * of the License, or (at your option) any later version. |
393 | + * |
394 | + * This program is distributed in the hope that it will be useful, |
395 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
396 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
397 | + * GNU General Public License for more details. |
398 | + * |
399 | + * You should have received a copy of the GNU General Public License |
400 | + * along with this program; if not, you may find one here: |
401 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
402 | + * or you may search the http://www.gnu.org website for the version 2 license, |
403 | + * or you may write to the Free Software Foundation, Inc., |
404 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
405 | + */ |
406 | + |
407 | +#ifndef KICAD_CLIPBOARD_H |
408 | +#define KICAD_CLIPBOARD_H |
409 | + |
410 | +#include <kicad_plugin.h> |
411 | +#include <class_board_item.h> |
412 | +#include <class_module.h> |
413 | +#include <pcb_parser.h> |
414 | +#include <memory.h> |
415 | + |
416 | +#include <tool/selection.h> |
417 | + |
418 | +class CLIPBOARD_PARSER : public PCB_PARSER |
419 | +{ |
420 | +public: |
421 | + CLIPBOARD_PARSER( LINE_READER* aReader = NULL ): PCB_PARSER( aReader ) {}; |
422 | + |
423 | + MODULE* parseMODULE( wxArrayString* aInitialComments ) |
424 | + { |
425 | + MODULE* mod = PCB_PARSER::parseMODULE( aInitialComments ); |
426 | + |
427 | + //TODO: figure out better way of handling paths |
428 | + mod->SetPath( wxT( "" ) ); |
429 | + return mod; |
430 | + } |
431 | +}; |
432 | + |
433 | + |
434 | +class CLIPBOARD_IO : public PCB_IO |
435 | +{ |
436 | + |
437 | +public: |
438 | + /* Saves the entire board to the clipboard formatted using the PCB_IO formatting */ |
439 | + void Save( const wxString& aFileName, BOARD* aBoard, |
440 | + const PROPERTIES* aProperties = NULL ) override; |
441 | + /* Writes all the settings of the BOARD* set by setBoard() and then adds all |
442 | + * the BOARD_ITEM* found in selection formatted by PCB_IO to clipboard as a text |
443 | + */ |
444 | + void SaveSelection( const SELECTION& selected ); |
445 | + |
446 | + BOARD_ITEM* Parse(); |
447 | + |
448 | + BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL ) override; |
449 | + CLIPBOARD_IO(); |
450 | + ~CLIPBOARD_IO(); |
451 | + |
452 | + void SetBoard( BOARD* aBoard ); |
453 | + STRING_FORMATTER* GetFormatter(); |
454 | + |
455 | +private: |
456 | + void writeHeader( BOARD* aBoard ); |
457 | + |
458 | + STRING_FORMATTER m_formatter; |
459 | + CLIPBOARD_PARSER* m_parser; |
460 | +}; |
461 | + |
462 | + |
463 | +#endif /* KICAD_CLIPBOARD_H */ |
464 | diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp |
465 | index bdc632d..fbf7ee4 100644 |
466 | --- a/pcbnew/kicad_plugin.cpp |
467 | +++ b/pcbnew/kicad_plugin.cpp |
468 | @@ -527,9 +527,9 @@ void PCB_IO::formatLayer( const BOARD_ITEM* aItem ) const |
469 | m_out->Print( 0, " (layer %s)", m_out->Quotew( aItem->GetLayerName() ).c_str() ); |
470 | } |
471 | |
472 | - |
473 | -void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const |
474 | +void PCB_IO::formatSetup( BOARD* aBoard, int aNestLevel ) const |
475 | { |
476 | + |
477 | const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings(); |
478 | |
479 | m_out->Print( 0, "\n" ); |
480 | @@ -572,7 +572,8 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const |
481 | |
482 | // Save used non-copper layers in the order they are defined. |
483 | // desired sequence for non Cu BOARD layers. |
484 | - static const PCB_LAYER_ID non_cu[] = { |
485 | + static const PCB_LAYER_ID non_cu[] = |
486 | + { |
487 | B_Adhes, // 32 |
488 | F_Adhes, |
489 | B_Paste, |
490 | @@ -719,8 +720,96 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const |
491 | aBoard->GetPlotOptions().Format( m_out, aNestLevel+1 ); |
492 | |
493 | m_out->Print( aNestLevel, ")\n\n" ); |
494 | +} |
495 | |
496 | - // Save net codes and names |
497 | + |
498 | +void PCB_IO::formatGeneral( BOARD* aBoard, int aNestLevel ) const |
499 | +{ |
500 | + const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings(); |
501 | + |
502 | + m_out->Print( 0, "\n" ); |
503 | + m_out->Print( aNestLevel, "(general\n" ); |
504 | + // Write Bounding box info |
505 | + m_out->Print( aNestLevel+1, "(thickness %s)\n", |
506 | + FMTIU( dsnSettings.GetBoardThickness() ).c_str() ); |
507 | + |
508 | + m_out->Print( aNestLevel+1, "(drawings %d)\n", aBoard->Drawings().Size() ); |
509 | + m_out->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() ); |
510 | + m_out->Print( aNestLevel+1, "(zones %d)\n", aBoard->GetNumSegmZone() ); |
511 | + m_out->Print( aNestLevel+1, "(modules %d)\n", aBoard->m_Modules.GetCount() ); |
512 | + m_out->Print( aNestLevel+1, "(nets %d)\n", m_mapping->GetSize() ); |
513 | + m_out->Print( aNestLevel, ")\n\n" ); |
514 | + |
515 | + aBoard->GetPageSettings().Format( m_out, aNestLevel, m_ctl ); |
516 | + aBoard->GetTitleBlock().Format( m_out, aNestLevel, m_ctl ); |
517 | +} |
518 | + |
519 | + |
520 | +void PCB_IO::formatBoardLayers( BOARD* aBoard, int aNestLevel ) const |
521 | +{ |
522 | + m_out->Print( aNestLevel, "(layers\n" ); |
523 | + |
524 | + // Save only the used copper layers from front to back. |
525 | + LSET visible_layers = aBoard->GetVisibleLayers(); |
526 | + |
527 | + for( LSEQ cu = aBoard->GetEnabledLayers().CuStack(); cu; ++cu ) |
528 | + { |
529 | + PCB_LAYER_ID layer = *cu; |
530 | + |
531 | + m_out->Print( aNestLevel+1, "(%d %s %s", layer, |
532 | + m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str(), |
533 | + LAYER::ShowType( aBoard->GetLayerType( layer ) ) ); |
534 | + |
535 | + if( !visible_layers[layer] ) |
536 | + m_out->Print( 0, " hide" ); |
537 | + |
538 | + m_out->Print( 0, ")\n" ); |
539 | + } |
540 | + |
541 | + // Save used non-copper layers in the order they are defined. |
542 | + // desired sequence for non Cu BOARD layers. |
543 | + static const PCB_LAYER_ID non_cu[] = |
544 | + { |
545 | + B_Adhes, // 32 |
546 | + F_Adhes, |
547 | + B_Paste, |
548 | + F_Paste, |
549 | + B_SilkS, |
550 | + F_SilkS, |
551 | + B_Mask, |
552 | + F_Mask, |
553 | + Dwgs_User, |
554 | + Cmts_User, |
555 | + Eco1_User, |
556 | + Eco2_User, |
557 | + Edge_Cuts, |
558 | + Margin, |
559 | + B_CrtYd, |
560 | + F_CrtYd, |
561 | + B_Fab, |
562 | + F_Fab |
563 | + }; |
564 | + |
565 | + for( LSEQ seq = aBoard->GetEnabledLayers().Seq( non_cu, DIM( non_cu ) ); seq; ++seq ) |
566 | + { |
567 | + PCB_LAYER_ID layer = *seq; |
568 | + |
569 | + m_out->Print( aNestLevel+1, "(%d %s user", layer, |
570 | + m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str() ); |
571 | + |
572 | + if( !visible_layers[layer] ) |
573 | + m_out->Print( 0, " hide" ); |
574 | + |
575 | + m_out->Print( 0, ")\n" ); |
576 | + } |
577 | + |
578 | + m_out->Print( aNestLevel, ")\n\n" ); |
579 | +} |
580 | + |
581 | + |
582 | +void PCB_IO::formatNetInformation( BOARD* aBoard, int aNestLevel ) const |
583 | +{ |
584 | + const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings(); |
585 | for( NETINFO_MAPPING::iterator net = m_mapping->begin(), netEnd = m_mapping->end(); |
586 | net != netEnd; ++net ) |
587 | { |
588 | @@ -745,6 +834,23 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const |
589 | filterNetClass( *aBoard, netclass ); // Remove empty nets (from a copy of a netclass) |
590 | netclass.Format( m_out, aNestLevel, m_ctl ); |
591 | } |
592 | +} |
593 | + |
594 | + |
595 | +void PCB_IO::formatHeader( BOARD* aBoard, int aNestLevel ) const |
596 | +{ |
597 | + formatGeneral( aBoard ); |
598 | + // Layers. |
599 | + formatBoardLayers( aBoard ); |
600 | + // Setup |
601 | + formatSetup( aBoard, aNestLevel ); |
602 | + // Save net codes and names |
603 | + formatNetInformation( aBoard, aNestLevel ); |
604 | +} |
605 | + |
606 | +void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const |
607 | +{ |
608 | + formatHeader( aBoard ); |
609 | |
610 | // Save the modules. |
611 | for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) |
612 | @@ -1541,7 +1647,7 @@ void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const |
613 | { |
614 | PCB_LAYER_ID layer1, layer2; |
615 | |
616 | - const VIA* via = static_cast<const VIA*>(aTrack); |
617 | + const VIA* via = static_cast<const VIA*>( aTrack ); |
618 | BOARD* board = (BOARD*) via->GetParent(); |
619 | |
620 | wxCHECK_RET( board != 0, wxT( "Via " ) + via->GetSelectMenuText() + |
621 | diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h |
622 | index 6ec6c7c..eff7590 100644 |
623 | --- a/pcbnew/kicad_plugin.h |
624 | +++ b/pcbnew/kicad_plugin.h |
625 | @@ -109,7 +109,7 @@ public: |
626 | return wxT( "kicad_pcb" ); |
627 | } |
628 | |
629 | - void Save( const wxString& aFileName, BOARD* aBoard, |
630 | + virtual void Save( const wxString& aFileName, BOARD* aBoard, |
631 | const PROPERTIES* aProperties = NULL ) override; |
632 | |
633 | BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, |
634 | @@ -188,6 +188,21 @@ protected: |
635 | |
636 | void init( const PROPERTIES* aProperties ); |
637 | |
638 | + /// formats the board setup information |
639 | + void formatSetup( BOARD* aBoard, int aNestLevel = 0 ) const; |
640 | + |
641 | + /// formats the General section of the file |
642 | + void formatGeneral( BOARD* aBoard, int aNestLevel = 0 ) const; |
643 | + |
644 | + /// formats the board layer information |
645 | + void formatBoardLayers( BOARD* aBoard, int aNestLevel = 0 ) const; |
646 | + |
647 | + /// formats the Nets and Netclasses |
648 | + void formatNetInformation( BOARD* aBoard, int aNestLevel = 0 ) const; |
649 | + |
650 | + /// writes everything that comes before the board_items, like settings and layers etc |
651 | + void formatHeader( BOARD* aBoard, int aNestLevel = 0 ) const; |
652 | + |
653 | private: |
654 | void format( BOARD* aBoard, int aNestLevel = 0 ) const; |
655 | |
656 | diff --git a/pcbnew/pcb_parser.h b/pcbnew/pcb_parser.h |
657 | index c03303c..b2ed26a 100644 |
658 | --- a/pcbnew/pcb_parser.h |
659 | +++ b/pcbnew/pcb_parser.h |
660 | @@ -119,14 +119,6 @@ class PCB_PARSER : public PCB_LEXER |
661 | DIMENSION* parseDIMENSION(); |
662 | |
663 | /** |
664 | - * Function parseMODULE |
665 | - * @param aInitialComments may be a pointer to a heap allocated initial comment block |
666 | - * or NULL. If not NULL, then caller has given ownership of a wxArrayString to |
667 | - * this function and care must be taken to delete it even on exception. |
668 | - */ |
669 | - MODULE* parseMODULE( wxArrayString* aInitialComments = 0 ); |
670 | - |
671 | - /** |
672 | * Function parseMODULE_unchecked |
673 | * Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically. |
674 | */ |
675 | @@ -309,6 +301,13 @@ public: |
676 | } |
677 | |
678 | BOARD_ITEM* Parse(); |
679 | + /** |
680 | + * Function parseMODULE |
681 | + * @param aInitialComments may be a pointer to a heap allocated initial comment block |
682 | + * or NULL. If not NULL, then caller has given ownership of a wxArrayString to |
683 | + * this function and care must be taken to delete it even on exception. |
684 | + */ |
685 | + MODULE* parseMODULE( wxArrayString* aInitialComments = 0 ); |
686 | |
687 | /** |
688 | * Return whether a version number, if any was parsed, was too recent |
689 | @@ -327,4 +326,5 @@ public: |
690 | }; |
691 | |
692 | |
693 | + |
694 | #endif // _PCBNEW_PARSER_H_ |
695 | diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp |
696 | index ef6cc2b..ea734a5 100644 |
697 | --- a/pcbnew/tools/edit_tool.cpp |
698 | +++ b/pcbnew/tools/edit_tool.cpp |
699 | @@ -54,7 +54,10 @@ using namespace std::placeholders; |
700 | #include "pcb_actions.h" |
701 | #include "selection_tool.h" |
702 | #include "edit_tool.h" |
703 | +#include "picker_tool.h" |
704 | #include "grid_helper.h" |
705 | +#include "kicad_clipboard.h" |
706 | +#include "pcbnew_control.h" |
707 | |
708 | #include <router/router_tool.h> |
709 | |
710 | @@ -161,6 +164,16 @@ TOOL_ACTION PCB_ACTIONS::measureTool( "pcbnew.InteractiveEdit.measureTool", |
711 | _( "Measuring tool" ), _( "Interactively measure distance between points" ), |
712 | nullptr, AF_ACTIVATE ); |
713 | |
714 | +TOOL_ACTION PCB_ACTIONS::copyToClipboard( "pcbnew.InteractiveEdit.CopyToClipboard", |
715 | + AS_GLOBAL, MD_CTRL + int( 'C' ), |
716 | + _( "Copy" ), _( "Copy selected content to clipboard" ), |
717 | + copy_xpm ); |
718 | + |
719 | +TOOL_ACTION PCB_ACTIONS::cutToClipboard( "pcbnew.InteractiveEdit.CutToClipboard", |
720 | + AS_GLOBAL, MD_CTRL + int( 'X' ), |
721 | + _( "Cut" ), _( "Cut selected content to clipboard" ), |
722 | + cut_xpm ); |
723 | + |
724 | static wxPoint getAnchorPoint( const SELECTION &selection, const MOVE_PARAMETERS ¶ms ) |
725 | { |
726 | wxPoint anchorPoint; |
727 | @@ -235,8 +248,6 @@ static wxPoint getAnchorPoint( const SELECTION &selection, const MOVE_PARAMETERS |
728 | } |
729 | |
730 | |
731 | - |
732 | - |
733 | EDIT_TOOL::EDIT_TOOL() : |
734 | PCB_TOOL( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), |
735 | m_dragging( false ) |
736 | @@ -289,6 +300,12 @@ bool EDIT_TOOL::Init() |
737 | menu.AddItem( PCB_ACTIONS::duplicate, SELECTION_CONDITIONS::NotEmpty ); |
738 | menu.AddItem( PCB_ACTIONS::createArray, SELECTION_CONDITIONS::NotEmpty ); |
739 | |
740 | + menu.AddSeparator(); |
741 | + menu.AddItem( PCB_ACTIONS::copyToClipboard, SELECTION_CONDITIONS::NotEmpty ); |
742 | + menu.AddItem( PCB_ACTIONS::cutToClipboard, SELECTION_CONDITIONS::NotEmpty ); |
743 | + menu.AddItem( PCB_ACTIONS::pasteFromClipboard ); |
744 | + menu.AddSeparator(); |
745 | + |
746 | // Mirror only available in modedit |
747 | menu.AddItem( PCB_ACTIONS::mirror, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty ); |
748 | |
749 | @@ -376,10 +393,10 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) |
750 | controls->SetAutoPan( true ); |
751 | |
752 | // cumulative translation |
753 | - wxPoint totalMovement( 0, 0 ); |
754 | - |
755 | + VECTOR2I totalMovement; |
756 | GRID_HELPER grid( editFrame ); |
757 | OPT_TOOL_EVENT evt = aEvent; |
758 | + VECTOR2I prevPos; |
759 | |
760 | // Main loop: keep receiving events |
761 | do |
762 | @@ -398,14 +415,20 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) |
763 | if( m_dragging && evt->Category() == TC_MOUSE ) |
764 | { |
765 | m_cursor = grid.BestSnapAnchor( evt->Position(), curr_item ); |
766 | + |
767 | controls->ForceCursorPosition( true, m_cursor ); |
768 | |
769 | - wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - curr_item->GetPosition(); |
770 | + VECTOR2I movement( m_cursor - prevPos );// - curr_item->GetPosition(); |
771 | + |
772 | totalMovement += movement; |
773 | + prevPos = m_cursor; |
774 | + auto delta = movement + m_offset; |
775 | |
776 | // Drag items to the current cursor position |
777 | for( auto item : selection ) |
778 | - static_cast<BOARD_ITEM*>( item )->Move( movement + m_offset ); |
779 | + static_cast<BOARD_ITEM*>( item )->Move( wxPoint( delta.x, delta.y ) ); |
780 | + |
781 | + m_offset = VECTOR2I(0, 0); |
782 | } |
783 | else if( !m_dragging ) // Prepare to start dragging |
784 | { |
785 | @@ -429,8 +452,25 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) |
786 | m_commit->Modify( item ); |
787 | |
788 | m_cursor = controls->GetCursorPosition(); |
789 | + m_offset = VECTOR2I(0, 0); |
790 | |
791 | - if( selection.Size() == 1 ) |
792 | + auto refPoint = VECTOR2I( curr_item->GetPosition() ); |
793 | + |
794 | + if ( selection.HasReferencePoint() ) |
795 | + { |
796 | + // start moving with the reference point attached to the cursor |
797 | + refPoint = selection.GetReferencePoint(); |
798 | + grid.SetAuxAxes( false ); |
799 | + |
800 | + auto delta = m_cursor - selection.GetReferencePoint(); |
801 | + |
802 | + // Drag items to the current cursor position |
803 | + for( auto item : selection ) |
804 | + static_cast<BOARD_ITEM*>( item )->Move( wxPoint( delta.x, delta.y ) ); |
805 | + |
806 | + selection.ClearReferencePoint(); |
807 | + } |
808 | + else if( selection.Size() == 1 ) |
809 | { |
810 | // Set the current cursor position to the first dragged item origin, so the |
811 | // movement vector could be computed later |
812 | @@ -444,10 +484,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) |
813 | |
814 | controls->SetCursorPosition( m_cursor, false ); |
815 | |
816 | - VECTOR2I o = VECTOR2I( curr_item->GetPosition() ); |
817 | - m_offset.x = o.x - m_cursor.x; |
818 | - m_offset.y = o.y - m_cursor.y; |
819 | - |
820 | + prevPos = m_cursor; |
821 | controls->SetAutoPan( true ); |
822 | m_dragging = true; |
823 | } |
824 | @@ -495,7 +532,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) |
825 | for( auto item : selection ) |
826 | { |
827 | BOARD_ITEM* i = static_cast<BOARD_ITEM*>( item ); |
828 | - i->SetPosition( i->GetPosition() - totalMovement ); |
829 | + auto delta = VECTOR2I( i->GetPosition() ) - totalMovement; |
830 | + i->SetPosition( wxPoint( delta.x, delta.y ) ); |
831 | |
832 | // And what about flipping and rotation? |
833 | // for now, they won't be undone, but maybe that is how |
834 | @@ -1211,6 +1249,10 @@ void EDIT_TOOL::setTransitions() |
835 | Go( &EDIT_TOOL::editFootprintInFpEditor, PCB_ACTIONS::editFootprintInFpEditor.MakeEvent() ); |
836 | Go( &EDIT_TOOL::ExchangeFootprints, PCB_ACTIONS::exchangeFootprints.MakeEvent() ); |
837 | Go( &EDIT_TOOL::MeasureTool, PCB_ACTIONS::measureTool.MakeEvent() ); |
838 | + |
839 | + Go( &EDIT_TOOL::copyToClipboard, PCB_ACTIONS::copyToClipboard.MakeEvent() ); |
840 | + Go( &EDIT_TOOL::cutToClipboard, PCB_ACTIONS::cutToClipboard.MakeEvent() ); |
841 | + |
842 | } |
843 | |
844 | |
845 | @@ -1218,7 +1260,9 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection ) |
846 | { |
847 | if( aSelection.Size() == 1 ) |
848 | { |
849 | - return static_cast<BOARD_ITEM*>( aSelection.Front() )->GetPosition() - m_offset; |
850 | + auto item = static_cast<BOARD_ITEM*>( aSelection.Front() ); |
851 | + auto pos = item->GetPosition(); |
852 | + return wxPoint( pos.x - m_offset.x, pos.y - m_offset.y ); |
853 | } |
854 | else |
855 | { |
856 | @@ -1268,6 +1312,50 @@ int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) |
857 | return 0; |
858 | } |
859 | |
860 | +bool EDIT_TOOL::pickCopyReferencePoint( VECTOR2I& aP ) |
861 | +{ |
862 | + PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>(); |
863 | + assert( picker ); |
864 | + |
865 | + picker->Activate(); |
866 | + |
867 | + while ( picker->IsPicking() ) |
868 | + Wait(); |
869 | + |
870 | + if( !picker->GetPoint() ) |
871 | + return false; |
872 | + |
873 | + aP = *picker->GetPoint(); |
874 | + return true; |
875 | +} |
876 | + |
877 | +int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent ) |
878 | +{ |
879 | + CLIPBOARD_IO io; |
880 | + BOARD* board = getModel<BOARD>(); |
881 | + VECTOR2I refPoint; |
882 | + |
883 | + Activate(); |
884 | + |
885 | + SELECTION selection = m_selectionTool->RequestSelection(); |
886 | + |
887 | + if( !pickCopyReferencePoint( refPoint ) ) |
888 | + return 0; |
889 | + |
890 | + selection.SetReferencePoint( refPoint ); |
891 | + io.SetBoard( board ); |
892 | + io.SaveSelection( selection ); |
893 | + |
894 | + return 0; |
895 | +} |
896 | + |
897 | +int EDIT_TOOL::cutToClipboard( const TOOL_EVENT& aEvent ) |
898 | +{ |
899 | + copyToClipboard( aEvent ); |
900 | + Remove( aEvent ); |
901 | + return 0; |
902 | +} |
903 | + |
904 | |
905 | template<class T> |
906 | T* EDIT_TOOL::uniqueSelected() |
907 | diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h |
908 | index 0868c68..0e19c44 100644 |
909 | --- a/pcbnew/tools/edit_tool.h |
910 | +++ b/pcbnew/tools/edit_tool.h |
911 | @@ -139,6 +139,28 @@ public: |
912 | ///> Sets up handlers for various events. |
913 | void setTransitions() override; |
914 | |
915 | + /** |
916 | + * Function copyToClipboard() |
917 | + * Sends the current selection to the clipboard by formatting it as a fake pcb |
918 | + * see AppendBoardFromClipboard for importing |
919 | + * @return True if it was sent succesfully |
920 | + */ |
921 | + int copyToClipboard( const TOOL_EVENT& aEvent ); |
922 | + |
923 | + /** |
924 | + * Function cutToClipboard() |
925 | + * Sends the current selection to the clipboard by formatting it as a fake pcb |
926 | + * see AppendBoardFromClipboard for importing |
927 | + * @return True if it was sent succesfully |
928 | + */ |
929 | + int cutToClipboard( const TOOL_EVENT& aEvent ); |
930 | + |
931 | + |
932 | + BOARD_COMMIT* GetCurrentCommit() const |
933 | + { |
934 | + return m_commit.get(); |
935 | + } |
936 | + |
937 | private: |
938 | ///> Selection tool used for obtaining selected items |
939 | SELECTION_TOOL* m_selectionTool; |
940 | @@ -147,7 +169,7 @@ private: |
941 | bool m_dragging; |
942 | |
943 | ///> Offset from the dragged item's center (anchor) |
944 | - wxPoint m_offset; |
945 | + VECTOR2I m_offset; |
946 | |
947 | ///> Last cursor position (needed for getModificationPoint() to avoid changes |
948 | ///> of edit reference point). |
949 | @@ -163,6 +185,7 @@ private: |
950 | bool isInteractiveDragEnabled() const; |
951 | |
952 | bool changeTrackWidthOnClick( const SELECTION& selection ); |
953 | + bool pickCopyReferencePoint( VECTOR2I& aP ); |
954 | |
955 | |
956 | /** |
957 | diff --git a/pcbnew/tools/grid_helper.cpp b/pcbnew/tools/grid_helper.cpp |
958 | index 7dce3b0..f01f2f8 100644 |
959 | --- a/pcbnew/tools/grid_helper.cpp |
960 | +++ b/pcbnew/tools/grid_helper.cpp |
961 | @@ -251,7 +251,13 @@ VECTOR2I GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, BOARD_ITEM* aDrag |
962 | computeAnchors( item, aOrigin ); |
963 | } |
964 | |
965 | - LSET layers( aDraggedItem->GetLayer() ); |
966 | + LSET layers; |
967 | + |
968 | + if( aDraggedItem ) |
969 | + layers = aDraggedItem->GetLayer(); |
970 | + else |
971 | + layers = LSET::AllLayersMask(); |
972 | + |
973 | ANCHOR* nearest = nearestAnchor( aOrigin, CORNER | SNAPPABLE, layers ); |
974 | |
975 | VECTOR2I nearestGrid = Align( aOrigin ); |
976 | diff --git a/pcbnew/tools/module_editor_tools.cpp b/pcbnew/tools/module_editor_tools.cpp |
977 | index 7c02ad5..7357b76 100644 |
978 | --- a/pcbnew/tools/module_editor_tools.cpp |
979 | +++ b/pcbnew/tools/module_editor_tools.cpp |
980 | @@ -23,6 +23,7 @@ |
981 | */ |
982 | |
983 | #include "module_editor_tools.h" |
984 | +#include "kicad_clipboard.h" |
985 | #include "selection_tool.h" |
986 | #include "pcb_actions.h" |
987 | #include <tool/tool_manager.h> |
988 | @@ -63,11 +64,11 @@ TOOL_ACTION PCB_ACTIONS::enumeratePads( "pcbnew.ModuleEditor.enumeratePads", |
989 | _( "Enumerate Pads" ), _( "Enumerate pads" ), pad_enumerate_xpm, AF_ACTIVATE ); |
990 | |
991 | TOOL_ACTION PCB_ACTIONS::copyItems( "pcbnew.ModuleEditor.copyItems", |
992 | - AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_COPY_ITEM ), |
993 | + AS_ACTIVE, 0, |
994 | _( "Copy" ), _( "Copy items" ), NULL, AF_ACTIVATE ); |
995 | |
996 | TOOL_ACTION PCB_ACTIONS::pasteItems( "pcbnew.ModuleEditor.pasteItems", |
997 | - AS_GLOBAL, MD_CTRL + int( 'V' ), |
998 | + AS_GLOBAL, 0, |
999 | _( "Paste" ), _( "Paste items" ), NULL, AF_ACTIVATE ); |
1000 | |
1001 | TOOL_ACTION PCB_ACTIONS::moduleEdgeOutlines( "pcbnew.ModuleEditor.graphicOutlines", |
1002 | @@ -333,21 +334,8 @@ int MODULE_EDITOR_TOOLS::CopyItems( const TOOL_EVENT& aEvent ) |
1003 | |
1004 | int MODULE_EDITOR_TOOLS::PasteItems( const TOOL_EVENT& aEvent ) |
1005 | { |
1006 | - // Parse clipboard |
1007 | - PCB_IO io( CTL_FOR_CLIPBOARD ); |
1008 | - MODULE* pastedModule = NULL; |
1009 | |
1010 | - try |
1011 | - { |
1012 | - BOARD_ITEM* item = io.Parse( wxString( m_toolMgr->GetClipboard().c_str(), wxConvUTF8 ) ); |
1013 | - assert( item->Type() == PCB_MODULE_T ); |
1014 | - pastedModule = dyn_cast<MODULE*>( item ); |
1015 | - } |
1016 | - catch( ... ) |
1017 | - { |
1018 | - frame()->DisplayToolMsg( _( "Invalid clipboard contents" ) ); |
1019 | - return 0; |
1020 | - } |
1021 | + MODULE* pastedModule = aEvent.Parameter<MODULE*>(); |
1022 | |
1023 | // Placement tool part |
1024 | VECTOR2I cursorPos = getViewControls()->GetCursorPosition(); |
1025 | @@ -427,7 +415,6 @@ int MODULE_EDITOR_TOOLS::PasteItems( const TOOL_EVENT& aEvent ) |
1026 | // Whyyyyyyyyyyyyyyyyyyyyyy?! All other items conform to rotation performed |
1027 | // on its parent module, but texts are so independent.. |
1028 | text->Rotate( text->GetPosition(), pastedModule->GetOrientation() ); |
1029 | - commit.Add( text ); |
1030 | } |
1031 | |
1032 | commit.Add( clone ); |
1033 | diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h |
1034 | index b82f142..008213e 100644 |
1035 | --- a/pcbnew/tools/pcb_actions.h |
1036 | +++ b/pcbnew/tools/pcb_actions.h |
1037 | @@ -82,6 +82,7 @@ public: |
1038 | /// Filters the items in the current selection (invokes dialog) |
1039 | static TOOL_ACTION filterSelection; |
1040 | |
1041 | + |
1042 | // Edit Tool |
1043 | /// Activation of the edit tool |
1044 | static TOOL_ACTION editActivate; |
1045 | @@ -300,6 +301,15 @@ public: |
1046 | /// Pasting module items from clipboard |
1047 | static TOOL_ACTION pasteItems; |
1048 | |
1049 | + /// Copy selected items to clipboard |
1050 | + static TOOL_ACTION copyToClipboard; |
1051 | + |
1052 | + /// Paste from clipboard |
1053 | + static TOOL_ACTION pasteFromClipboard; |
1054 | + |
1055 | + /// Paste from clipboard |
1056 | + static TOOL_ACTION cutToClipboard; |
1057 | + |
1058 | /// Display module edges as outlines |
1059 | static TOOL_ACTION moduleEdgeOutlines; |
1060 | |
1061 | diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp |
1062 | index 438d521..0815944 100644 |
1063 | --- a/pcbnew/tools/pcb_editor_control.cpp |
1064 | +++ b/pcbnew/tools/pcb_editor_control.cpp |
1065 | @@ -390,7 +390,7 @@ int PCB_EDITOR_CONTROL::ViaSizeDec( const TOOL_EVENT& aEvent ) |
1066 | |
1067 | int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) |
1068 | { |
1069 | - MODULE* module = NULL; |
1070 | + MODULE* module = aEvent.Parameter<MODULE*>(); |
1071 | KIGFX::VIEW* view = getView(); |
1072 | KIGFX::VIEW_CONTROLS* controls = getViewControls(); |
1073 | BOARD* board = getModel<BOARD>(); |
1074 | @@ -406,10 +406,20 @@ int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) |
1075 | Activate(); |
1076 | m_frame->SetToolID( ID_PCB_MODULE_BUTT, wxCURSOR_PENCIL, _( "Add footprint" ) ); |
1077 | |
1078 | + // Add all the drawable parts to preview |
1079 | + VECTOR2I cursorPos = controls->GetCursorPosition(); |
1080 | + if( module ) |
1081 | + { |
1082 | + module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); |
1083 | + preview.Add( module ); |
1084 | + module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); |
1085 | + view->Update( &preview ); |
1086 | + } |
1087 | + |
1088 | // Main loop: keep receiving events |
1089 | while( OPT_TOOL_EVENT evt = Wait() ) |
1090 | { |
1091 | - VECTOR2I cursorPos = controls->GetCursorPosition(); |
1092 | + cursorPos = controls->GetCursorPosition(); |
1093 | |
1094 | if( evt->IsCancel() || evt->IsActivate() ) |
1095 | { |
1096 | diff --git a/pcbnew/tools/pcb_tool.h b/pcbnew/tools/pcb_tool.h |
1097 | index 2c83ff9..0d98f92 100644 |
1098 | --- a/pcbnew/tools/pcb_tool.h |
1099 | +++ b/pcbnew/tools/pcb_tool.h |
1100 | @@ -124,6 +124,8 @@ protected: |
1101 | KIGFX::VIEW_CONTROLS* controls() const { return getViewControls(); } |
1102 | PCB_EDIT_FRAME* frame() const { return getEditFrame<PCB_EDIT_FRAME>(); } |
1103 | BOARD* board() const { return getModel<BOARD>(); } |
1104 | + MODULE* module() const { return board()->m_Modules; } |
1105 | + |
1106 | |
1107 | bool m_editModules; |
1108 | }; |
1109 | diff --git a/pcbnew/tools/pcbnew_control.cpp b/pcbnew/tools/pcbnew_control.cpp |
1110 | index 3ef2490..24bb034 100644 |
1111 | --- a/pcbnew/tools/pcbnew_control.cpp |
1112 | +++ b/pcbnew/tools/pcbnew_control.cpp |
1113 | @@ -27,7 +27,9 @@ |
1114 | #include "pcbnew_control.h" |
1115 | #include "pcb_actions.h" |
1116 | #include "selection_tool.h" |
1117 | +#include "edit_tool.h" |
1118 | #include "picker_tool.h" |
1119 | +#include "pcb_editor_control.h" |
1120 | #include "grid_helper.h" |
1121 | |
1122 | #include <class_board.h> |
1123 | @@ -40,6 +42,8 @@ |
1124 | #include <hotkeys.h> |
1125 | #include <properties.h> |
1126 | #include <io_mgr.h> |
1127 | +#include <kicad_plugin.h> |
1128 | +#include <kicad_clipboard.h> |
1129 | |
1130 | #include <pcbnew_id.h> |
1131 | #include <wxPcbStruct.h> |
1132 | @@ -51,6 +55,7 @@ |
1133 | #include <pcb_painter.h> |
1134 | #include <origin_viewitem.h> |
1135 | #include <board_commit.h> |
1136 | +#include <bitmaps.h> |
1137 | |
1138 | #include <functional> |
1139 | using namespace std::placeholders; |
1140 | @@ -221,9 +226,14 @@ TOOL_ACTION PCB_ACTIONS::toBeDone( "pcbnew.Control.toBeDone", |
1141 | AS_GLOBAL, 0, // dialog saying it is not implemented yet |
1142 | "", "" ); // so users are aware of that |
1143 | |
1144 | +TOOL_ACTION PCB_ACTIONS::pasteFromClipboard( "pcbnew.InteractiveEdit.pasteFromClipboard", |
1145 | + AS_GLOBAL, MD_CTRL + int( 'V' ), |
1146 | + _( "Paste" ), _( "Paste content from clipboard" ), |
1147 | + paste_xpm ); |
1148 | + |
1149 | |
1150 | PCBNEW_CONTROL::PCBNEW_CONTROL() : |
1151 | - TOOL_INTERACTIVE( "pcbnew.Control" ), m_frame( NULL ) |
1152 | + PCB_TOOL( "pcbnew.Control" ), m_frame( NULL ) |
1153 | { |
1154 | m_gridOrigin.reset( new KIGFX::ORIGIN_VIEWITEM() ); |
1155 | } |
1156 | @@ -240,7 +250,7 @@ void PCBNEW_CONTROL::Reset( RESET_REASON aReason ) |
1157 | |
1158 | if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH ) |
1159 | { |
1160 | - m_gridOrigin->SetPosition( getModel<BOARD>()->GetGridOrigin() ); |
1161 | + m_gridOrigin->SetPosition( board()->GetGridOrigin() ); |
1162 | getView()->Remove( m_gridOrigin.get() ); |
1163 | getView()->Add( m_gridOrigin.get() ); |
1164 | } |
1165 | @@ -257,10 +267,10 @@ int PCBNEW_CONTROL::TrackDisplayMode( const TOOL_EVENT& aEvent ) |
1166 | displ_opts->m_DisplayPcbTrackFill = !displ_opts->m_DisplayPcbTrackFill; |
1167 | settings->LoadDisplayOptions( displ_opts ); |
1168 | |
1169 | - for( TRACK* track = getModel<BOARD>()->m_Track; track; track = track->Next() ) |
1170 | + for( auto track : board()->Tracks() ) |
1171 | { |
1172 | if( track->Type() == PCB_TRACE_T ) |
1173 | - getView()->Update( track, KIGFX::GEOMETRY ); |
1174 | + view()->Update( track, KIGFX::GEOMETRY ); |
1175 | } |
1176 | |
1177 | m_frame->GetGalCanvas()->Refresh(); |
1178 | @@ -280,7 +290,7 @@ int PCBNEW_CONTROL::PadDisplayMode( const TOOL_EVENT& aEvent ) |
1179 | displ_opts->m_DisplayPadFill = !displ_opts->m_DisplayPadFill; |
1180 | settings->LoadDisplayOptions( displ_opts ); |
1181 | |
1182 | - for( MODULE* module = getModel<BOARD>()->m_Modules; module; module = module->Next() ) |
1183 | + for( auto module : board()->Modules() ) |
1184 | { |
1185 | for( auto pad : module->Pads() ) |
1186 | getView()->Update( pad, KIGFX::GEOMETRY ); |
1187 | @@ -302,7 +312,7 @@ int PCBNEW_CONTROL::ViaDisplayMode( const TOOL_EVENT& aEvent ) |
1188 | displ_opts->m_DisplayViaFill = !displ_opts->m_DisplayViaFill; |
1189 | settings->LoadDisplayOptions( displ_opts ); |
1190 | |
1191 | - for( TRACK* track = getModel<BOARD>()->m_Track; track; track = track->Next() ) |
1192 | + for( auto track : board()->Tracks() ) |
1193 | { |
1194 | if( track->Type() == PCB_TRACE_T || track->Type() == PCB_VIA_T ) |
1195 | getView()->Update( track, KIGFX::GEOMETRY ); |
1196 | @@ -332,9 +342,8 @@ int PCBNEW_CONTROL::ZoneDisplayMode( const TOOL_EVENT& aEvent ) |
1197 | |
1198 | settings->LoadDisplayOptions( displ_opts ); |
1199 | |
1200 | - BOARD* board = getModel<BOARD>(); |
1201 | - for( int i = 0; i < board->GetAreaCount(); ++i ) |
1202 | - getView()->Update( board->GetArea( i ), KIGFX::GEOMETRY ); |
1203 | + for( int i = 0; i < board()->GetAreaCount(); ++i ) |
1204 | + view()->Update( board()->GetArea( i ), KIGFX::GEOMETRY ); |
1205 | |
1206 | m_frame->GetGalCanvas()->Refresh(); |
1207 | |
1208 | @@ -385,7 +394,7 @@ int PCBNEW_CONTROL::LayerNext( const TOOL_EVENT& aEvent ) |
1209 | if( layer < F_Cu || layer > B_Cu ) |
1210 | return 0; |
1211 | |
1212 | - int layerCount = getModel<BOARD>()->GetCopperLayerCount(); |
1213 | + int layerCount = board()->GetCopperLayerCount(); |
1214 | |
1215 | if( layer == layerCount - 2 || layerCount < 2 ) |
1216 | layer = B_Cu; |
1217 | @@ -409,7 +418,7 @@ int PCBNEW_CONTROL::LayerPrev( const TOOL_EVENT& aEvent ) |
1218 | if( layer < F_Cu || layer > B_Cu ) |
1219 | return 0; |
1220 | |
1221 | - int layerCount = getModel<BOARD>()->GetCopperLayerCount(); |
1222 | + int layerCount = board()->GetCopperLayerCount(); |
1223 | |
1224 | if( layer == F_Cu || layerCount < 2 ) |
1225 | layer = B_Cu; |
1226 | @@ -640,7 +649,7 @@ int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent ) |
1227 | |
1228 | int PCBNEW_CONTROL::GridResetOrigin( const TOOL_EVENT& aEvent ) |
1229 | { |
1230 | - getModel<BOARD>()->SetGridOrigin( wxPoint( 0, 0 ) ); |
1231 | + board()->SetGridOrigin( wxPoint( 0, 0 ) ); |
1232 | m_gridOrigin->SetPosition( VECTOR2D( 0, 0 ) ); |
1233 | |
1234 | return 0; |
1235 | @@ -729,7 +738,83 @@ int PCBNEW_CONTROL::DeleteItemCursor( const TOOL_EVENT& aEvent ) |
1236 | } |
1237 | |
1238 | |
1239 | -int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) |
1240 | +int PCBNEW_CONTROL::PasteItemsFromClipboard( const TOOL_EVENT& aEvent ) |
1241 | +{ |
1242 | + CLIPBOARD_IO pi; |
1243 | + |
1244 | + pi.SetBoard( board() ); |
1245 | + BOARD_ITEM* clipItem = pi.Parse(); |
1246 | + |
1247 | + if(!clipItem ) |
1248 | + { |
1249 | + return 0; |
1250 | + } |
1251 | + |
1252 | + bool editModules = m_editModules || frame()->IsType( FRAME_PCB_MODULE_EDITOR ); |
1253 | + |
1254 | + // The clipboard can contain two different things, an entire kicad_pcb |
1255 | + // or a single module |
1256 | + |
1257 | + if ( editModules && ( !board() || !module() ) ) |
1258 | + { |
1259 | + wxLogDebug( wxT( "Attempting to paste to empty module editor window\n") ); |
1260 | + return 0; |
1261 | + } |
1262 | + |
1263 | + |
1264 | + switch( clipItem->Type() ) |
1265 | + { |
1266 | + case PCB_T: |
1267 | + { |
1268 | + if( editModules ) |
1269 | + { |
1270 | + wxLogDebug( wxT( "attempting to paste a pcb in the footprint editor\n") ); |
1271 | + return 0; |
1272 | + } |
1273 | + |
1274 | + placeBoardItems( static_cast<BOARD*>( clipItem ) ); |
1275 | + break; |
1276 | + } |
1277 | + |
1278 | + case PCB_MODULE_T: |
1279 | + { |
1280 | + std::vector<BOARD_ITEM *> items; |
1281 | + |
1282 | + clipItem->SetParent( board() ); |
1283 | + |
1284 | + if( editModules ) |
1285 | + { |
1286 | + auto mod = static_cast<MODULE *>( clipItem ); |
1287 | + |
1288 | + for ( auto pad : mod->Pads() ) |
1289 | + { |
1290 | + pad->SetParent ( board()->m_Modules.GetFirst() ); |
1291 | + items.push_back( pad ); |
1292 | + } |
1293 | + for ( auto item : mod->GraphicalItems() ) |
1294 | + { |
1295 | + item->SetParent ( board()->m_Modules.GetFirst() ); |
1296 | + items.push_back( item ); |
1297 | + } |
1298 | + } |
1299 | + else |
1300 | + { |
1301 | + items.push_back( clipItem ); |
1302 | + } |
1303 | + |
1304 | + placeBoardItems( items ); |
1305 | + break; |
1306 | + } |
1307 | + default: |
1308 | + m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) ); |
1309 | + // FAILED |
1310 | + break; |
1311 | + } |
1312 | + return 1; |
1313 | +} |
1314 | + |
1315 | + |
1316 | +int PCBNEW_CONTROL::AppendBoardFromFile( const TOOL_EVENT& aEvent ) |
1317 | { |
1318 | int open_ctl; |
1319 | wxString fileName; |
1320 | @@ -737,31 +822,151 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) |
1321 | PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ); |
1322 | |
1323 | if( !editFrame ) |
1324 | - return 0; |
1325 | + return 1; |
1326 | |
1327 | // Pick a file to append |
1328 | if( !AskLoadBoardFileName( editFrame, &open_ctl, &fileName, true ) ) |
1329 | - return 0; |
1330 | + return 1; |
1331 | |
1332 | IO_MGR::PCB_FILE_T pluginType = plugin_type( fileName, open_ctl ); |
1333 | PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); |
1334 | |
1335 | + return AppendBoard( *pi, fileName ); |
1336 | +} |
1337 | + |
1338 | + |
1339 | +int PCBNEW_CONTROL::placeBoardItems( BOARD* aBoard ) |
1340 | +{ |
1341 | + std::vector<BOARD_ITEM*> items; |
1342 | + auto currentBoard = board(); |
1343 | + |
1344 | + PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ); |
1345 | + |
1346 | + if( currentBoard->GetCopperLayerCount() < aBoard->GetCopperLayerCount() ) |
1347 | + { |
1348 | + |
1349 | + if( !IsOK( editFrame, _( "Pasting will add extra layers to the PCB, continue? ") ) ) |
1350 | + return 0; |
1351 | + |
1352 | + currentBoard->SetCopperLayerCount( aBoard->GetCopperLayerCount() ); |
1353 | + currentBoard->SetEnabledLayers( aBoard->GetEnabledLayers() ); |
1354 | + |
1355 | + editFrame->ReCreateLayerBox(); |
1356 | + editFrame->ReFillLayerWidget(); |
1357 | + } |
1358 | + |
1359 | + for( auto track : aBoard->Tracks() ) |
1360 | + { |
1361 | + if( !currentBoard->FindNet( track->GetNetname() ) ) |
1362 | + { |
1363 | + NETINFO_ITEM* newNet = new NETINFO_ITEM( currentBoard, |
1364 | + track->GetNet()->GetNetname(), -1 ); |
1365 | + currentBoard->Add( newNet ); |
1366 | + currentBoard->BuildListOfNets(); |
1367 | + } |
1368 | + track->SetParent( currentBoard ); |
1369 | + track->SetNet( currentBoard->FindNet( track->GetNetname()) ); |
1370 | + items.push_back( track ); |
1371 | + } |
1372 | + |
1373 | + for( auto module : aBoard->Modules() ) |
1374 | + { |
1375 | + module->SetParent( currentBoard ); |
1376 | + for( auto pad : module->Pads() ) |
1377 | + { |
1378 | + // Check if the net is there by name, otherwise, add a new net and |
1379 | + // reassign the item to the new net |
1380 | + if( !currentBoard->FindNet( pad->GetNet()->GetNetname() ) ) |
1381 | + { |
1382 | + // A net with -1 in netcode will be autoassigned a net |
1383 | + NETINFO_ITEM* newNet = new NETINFO_ITEM( currentBoard, |
1384 | + pad->GetNet()->GetNetname(), -1 ); |
1385 | + currentBoard->Add( newNet ); |
1386 | + currentBoard->BuildListOfNets(); |
1387 | + } |
1388 | + pad->SetParent( module ); |
1389 | + pad->SetNet( currentBoard->FindNet( pad->GetNetname() ) ); |
1390 | + } |
1391 | + |
1392 | + items.push_back( module ); |
1393 | + } |
1394 | + |
1395 | + for( auto drawing : aBoard->Drawings() ) |
1396 | + { |
1397 | + items.push_back( drawing ); |
1398 | + } |
1399 | + |
1400 | + for( auto zone : aBoard->Zones() ) |
1401 | + { |
1402 | + // Check if the net is there by name, otherwise, add a new net and |
1403 | + // reassign the item to the new net |
1404 | + if( !currentBoard->FindNet( zone->GetNet()->GetNetname() ) ) |
1405 | + { |
1406 | + NETINFO_ITEM* newNet = new NETINFO_ITEM( currentBoard, |
1407 | + zone->GetNet()->GetNetname(), -1 ); |
1408 | + currentBoard->Add( newNet ); |
1409 | + currentBoard->BuildListOfNets(); |
1410 | + } |
1411 | + zone->SetParent( currentBoard ); |
1412 | + zone->SetNet( currentBoard->FindNet( zone->GetNetname() ) ); |
1413 | + items.push_back( zone ); |
1414 | + } |
1415 | + |
1416 | + // A lot of changes to the nets may have happen, be on the safe side |
1417 | + // and rebuild these things |
1418 | + currentBoard->BuildListOfNets(); |
1419 | + currentBoard->SynchronizeNetsAndNetClasses(); |
1420 | + currentBoard->GetConnectivity()->RecalculateRatsnest(); |
1421 | + |
1422 | + // the list of items should now be sanitized to fit on the current board |
1423 | + return placeBoardItems( items ); |
1424 | +} |
1425 | + |
1426 | + |
1427 | +int PCBNEW_CONTROL::placeBoardItems( std::vector<BOARD_ITEM*>& aItems ) |
1428 | +{ |
1429 | + m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); |
1430 | + |
1431 | + auto selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>(); |
1432 | + auto editTool = m_toolMgr->GetTool<EDIT_TOOL>(); |
1433 | + |
1434 | + SELECTION& selection = selectionTool->GetSelection(); |
1435 | + |
1436 | + for ( auto item : aItems ) |
1437 | + { |
1438 | + item->SetSelected(); |
1439 | + selection.Add( item ); |
1440 | + editTool->GetCurrentCommit()->Add( item ); |
1441 | + } |
1442 | + |
1443 | + selection.SetReferencePoint( VECTOR2I( 0, 0 ) ); |
1444 | + |
1445 | + m_toolMgr->ProcessEvent( SELECTION_TOOL::SelectedEvent ); |
1446 | + m_toolMgr->RunAction( PCB_ACTIONS::move, true ); |
1447 | + |
1448 | + return 0; |
1449 | +} |
1450 | + |
1451 | +int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName ) |
1452 | +{ |
1453 | + |
1454 | + PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ); |
1455 | + if( !editFrame ) |
1456 | + return 1; |
1457 | + |
1458 | // Mark existing tracks, in order to know what are the new tracks |
1459 | // Tracks are inserted, not appended, so mark existing tracks to be |
1460 | // able to select the new tracks only later |
1461 | - BOARD* board = getModel<BOARD>(); |
1462 | + BOARD* brd = board(); |
1463 | + if( !brd ) |
1464 | + return 1; |
1465 | |
1466 | - for( TRACK* track = board->m_Track; track; track = track->Next() ) |
1467 | + for( auto track : brd->Tracks() ) |
1468 | track->SetFlags( FLAG0 ); |
1469 | |
1470 | - // Other items are appended to the item list, so keep trace to the last existing item is enough |
1471 | - MODULE* module = board->m_Modules.GetLast(); |
1472 | - BOARD_ITEM* drawing = board->DrawingsList().GetLast(); |
1473 | - int zonescount = board->GetAreaCount(); |
1474 | - |
1475 | // Keep also the count of copper layers, to adjust if necessary |
1476 | - int initialCopperLayerCount = board->GetCopperLayerCount(); |
1477 | - LSET initialEnabledLayers = board->GetEnabledLayers(); |
1478 | + int initialCopperLayerCount = brd->GetCopperLayerCount(); |
1479 | + LSET initialEnabledLayers = brd->GetEnabledLayers(); |
1480 | |
1481 | // Load the data |
1482 | try |
1483 | @@ -778,7 +983,7 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) |
1484 | props["page_height"] = ybuf; |
1485 | |
1486 | editFrame->GetDesignSettings().m_NetClasses.Clear(); |
1487 | - pi->Load( fileName, board, &props ); |
1488 | + pi.Load( fileName, brd, &props ); |
1489 | } |
1490 | catch( const IO_ERROR& ioe ) |
1491 | { |
1492 | @@ -789,86 +994,25 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) |
1493 | } |
1494 | |
1495 | // rebuild nets and ratsnest before any use of nets |
1496 | - board->BuildListOfNets(); |
1497 | - board->SynchronizeNetsAndNetClasses(); |
1498 | - board->GetConnectivity()->Build( board ); |
1499 | - |
1500 | - m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); |
1501 | - |
1502 | - SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>(); |
1503 | - SELECTION& selection = selectionTool->GetSelection(); |
1504 | - BOARD_COMMIT commit( editFrame ); |
1505 | - |
1506 | - // Process the new items |
1507 | - for( TRACK* track = board->m_Track; track; track = track->Next() ) |
1508 | - { |
1509 | - if( track->GetFlags() & FLAG0 ) |
1510 | - { |
1511 | - track->ClearFlags( FLAG0 ); |
1512 | - continue; |
1513 | - } |
1514 | - |
1515 | - commit.Added( track ); |
1516 | - selection.Add( track ); |
1517 | - } |
1518 | - |
1519 | - module = module ? module->Next() : board->m_Modules; |
1520 | - |
1521 | - for( ; module; module = module->Next() ) |
1522 | - { |
1523 | - commit.Added( module ); |
1524 | - selection.Add( module ); |
1525 | - } |
1526 | - |
1527 | - drawing = drawing ? drawing->Next() : board->DrawingsList(); |
1528 | - |
1529 | - for( ; drawing; drawing = drawing->Next() ) |
1530 | - { |
1531 | - commit.Added( drawing ); |
1532 | - selection.Add( drawing ); |
1533 | - } |
1534 | + brd->BuildListOfNets(); |
1535 | + brd->SynchronizeNetsAndNetClasses(); |
1536 | |
1537 | - for( ZONE_CONTAINER* zone = board->GetArea( zonescount ); zone; |
1538 | - zone = board->GetArea( zonescount ) ) |
1539 | - { |
1540 | - ++zonescount; |
1541 | - commit.Added( zone ); |
1542 | - selection.Add( zone ); |
1543 | - } |
1544 | - |
1545 | - if( commit.Empty() ) |
1546 | - return 0; |
1547 | - |
1548 | - commit.Push( _( "Append a board" ) ); |
1549 | |
1550 | // Synchronize layers |
1551 | // we should not ask PLUGINs to do these items: |
1552 | - int copperLayerCount = board->GetCopperLayerCount(); |
1553 | + int copperLayerCount = brd->GetCopperLayerCount(); |
1554 | |
1555 | if( copperLayerCount > initialCopperLayerCount ) |
1556 | - board->SetCopperLayerCount( copperLayerCount ); |
1557 | + brd->SetCopperLayerCount( copperLayerCount ); |
1558 | |
1559 | // Enable all used layers, and make them visible: |
1560 | - LSET enabledLayers = board->GetEnabledLayers(); |
1561 | + LSET enabledLayers = brd->GetEnabledLayers(); |
1562 | enabledLayers |= initialEnabledLayers; |
1563 | - board->SetEnabledLayers( enabledLayers ); |
1564 | - board->SetVisibleLayers( enabledLayers ); |
1565 | - editFrame->ReCreateLayerBox(); |
1566 | - editFrame->ReFillLayerWidget(); |
1567 | - static_cast<PCB_DRAW_PANEL_GAL*>( editFrame->GetGalCanvas() )->SyncLayersVisibility( board ); |
1568 | - |
1569 | - // Start dragging the appended board |
1570 | - if( selection.Size() ) // be sure at least one item is loaded |
1571 | - { |
1572 | - // Inform other potentially interested tools |
1573 | - m_toolMgr->ProcessEvent( SELECTION_TOOL::SelectedEvent ); |
1574 | + brd->SetEnabledLayers( enabledLayers ); |
1575 | + brd->SetVisibleLayers( enabledLayers ); |
1576 | |
1577 | - VECTOR2D v( static_cast<BOARD_ITEM*>( selection.Front() )->GetPosition() ); |
1578 | - getViewControls()->WarpCursor( v, true, true ); |
1579 | - m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); |
1580 | - } |
1581 | |
1582 | - return 0; |
1583 | + return placeBoardItems( brd ); |
1584 | } |
1585 | |
1586 | |
1587 | @@ -945,9 +1089,15 @@ void PCBNEW_CONTROL::setTransitions() |
1588 | Go( &PCBNEW_CONTROL::SwitchCursor, PCB_ACTIONS::switchCursor.MakeEvent() ); |
1589 | Go( &PCBNEW_CONTROL::SwitchUnits, PCB_ACTIONS::switchUnits.MakeEvent() ); |
1590 | Go( &PCBNEW_CONTROL::DeleteItemCursor, PCB_ACTIONS::deleteItemCursor.MakeEvent() ); |
1591 | - Go( &PCBNEW_CONTROL::AppendBoard, PCB_ACTIONS::appendBoard.MakeEvent() ); |
1592 | Go( &PCBNEW_CONTROL::ShowHelp, PCB_ACTIONS::showHelp.MakeEvent() ); |
1593 | Go( &PCBNEW_CONTROL::ToBeDone, PCB_ACTIONS::toBeDone.MakeEvent() ); |
1594 | + |
1595 | + // Append control |
1596 | + Go( &PCBNEW_CONTROL::AppendBoardFromFile, |
1597 | + PCB_ACTIONS::appendBoard.MakeEvent() ); |
1598 | + |
1599 | + Go( &PCBNEW_CONTROL::PasteItemsFromClipboard, |
1600 | + PCB_ACTIONS::pasteFromClipboard.MakeEvent() ); |
1601 | } |
1602 | |
1603 | |
1604 | diff --git a/pcbnew/tools/pcbnew_control.h b/pcbnew/tools/pcbnew_control.h |
1605 | index 11131a2..a63bff6 100644 |
1606 | --- a/pcbnew/tools/pcbnew_control.h |
1607 | +++ b/pcbnew/tools/pcbnew_control.h |
1608 | @@ -25,21 +25,23 @@ |
1609 | #ifndef PCBNEW_CONTROL_H |
1610 | #define PCBNEW_CONTROL_H |
1611 | |
1612 | -#include <tool/tool_interactive.h> |
1613 | +#include <io_mgr.h> |
1614 | #include <memory> |
1615 | +#include <tools/pcb_tool.h> |
1616 | |
1617 | namespace KIGFX { |
1618 | class ORIGIN_VIEWITEM; |
1619 | } |
1620 | -class PCB_BASE_FRAME; |
1621 | |
1622 | +class PCB_BASE_FRAME; |
1623 | +class BOARD_ITEM; |
1624 | /** |
1625 | * Class PCBNEW_CONTROL |
1626 | * |
1627 | * Handles actions that are shared between different frames in pcbnew. |
1628 | */ |
1629 | |
1630 | -class PCBNEW_CONTROL : public TOOL_INTERACTIVE |
1631 | +class PCBNEW_CONTROL : public PCB_TOOL |
1632 | { |
1633 | public: |
1634 | PCBNEW_CONTROL(); |
1635 | @@ -79,7 +81,9 @@ public: |
1636 | int SwitchCursor( const TOOL_EVENT& aEvent ); |
1637 | int SwitchUnits( const TOOL_EVENT& aEvent ); |
1638 | int DeleteItemCursor( const TOOL_EVENT& aEvent ); |
1639 | - int AppendBoard( const TOOL_EVENT& aEvent ); |
1640 | + int PasteItemsFromClipboard( const TOOL_EVENT& aEvent ); |
1641 | + int AppendBoardFromFile( const TOOL_EVENT& aEvent ); |
1642 | + int AppendBoard( PLUGIN& pi, wxString& fileName ); |
1643 | int ShowHelp( const TOOL_EVENT& aEvent ); |
1644 | int ToBeDone( const TOOL_EVENT& aEvent ); |
1645 | |
1646 | @@ -87,6 +91,10 @@ public: |
1647 | void setTransitions() override; |
1648 | |
1649 | private: |
1650 | + |
1651 | + int placeBoardItems( BOARD* aBoard ); |
1652 | + int placeBoardItems( std::vector<BOARD_ITEM*>& aItems ); |
1653 | + |
1654 | ///> Pointer to the currently used edit frame. |
1655 | PCB_BASE_FRAME* m_frame; |
1656 | |
1657 | diff --git a/pcbnew/tools/picker_tool.cpp b/pcbnew/tools/picker_tool.cpp |
1658 | index 332aacf..a8e63d6 100644 |
1659 | --- a/pcbnew/tools/picker_tool.cpp |
1660 | +++ b/pcbnew/tools/picker_tool.cpp |
1661 | @@ -24,6 +24,7 @@ |
1662 | |
1663 | #include "picker_tool.h" |
1664 | #include "pcb_actions.h" |
1665 | +#include "grid_helper.h" |
1666 | |
1667 | #include <wxPcbStruct.h> |
1668 | #include <view/view_controls.h> |
1669 | @@ -33,7 +34,7 @@ TOOL_ACTION PCB_ACTIONS::pickerTool( "pcbnew.Picker", AS_GLOBAL, 0, "", "", NULL |
1670 | |
1671 | |
1672 | PICKER_TOOL::PICKER_TOOL() |
1673 | - : TOOL_INTERACTIVE( "pcbnew.Picker" ) |
1674 | + : PCB_TOOL( "pcbnew.Picker" ) |
1675 | { |
1676 | reset(); |
1677 | } |
1678 | @@ -42,6 +43,7 @@ PICKER_TOOL::PICKER_TOOL() |
1679 | int PICKER_TOOL::Main( const TOOL_EVENT& aEvent ) |
1680 | { |
1681 | KIGFX::VIEW_CONTROLS* controls = getViewControls(); |
1682 | + GRID_HELPER grid( frame() ); |
1683 | |
1684 | assert( !m_picking ); |
1685 | m_picking = true; |
1686 | @@ -49,13 +51,19 @@ int PICKER_TOOL::Main( const TOOL_EVENT& aEvent ) |
1687 | |
1688 | setControls(); |
1689 | |
1690 | + |
1691 | while( OPT_TOOL_EVENT evt = Wait() ) |
1692 | { |
1693 | + auto mousePos = controls->GetMousePosition(); |
1694 | + auto p = grid.BestSnapAnchor( mousePos, nullptr ); |
1695 | + controls->ForceCursorPosition( true, p ); |
1696 | + |
1697 | if( evt->IsClick( BUT_LEFT ) ) |
1698 | { |
1699 | bool getNext = false; |
1700 | - m_picked = controls->GetCursorPosition(); |
1701 | |
1702 | + m_picked = p; |
1703 | + |
1704 | if( m_clickHandler ) |
1705 | { |
1706 | try |
1707 | @@ -83,6 +91,7 @@ int PICKER_TOOL::Main( const TOOL_EVENT& aEvent ) |
1708 | } |
1709 | |
1710 | reset(); |
1711 | + controls->ForceCursorPosition( false ); |
1712 | getEditFrame<PCB_BASE_FRAME>()->SetNoToolSelected(); |
1713 | |
1714 | return 0; |
1715 | diff --git a/pcbnew/tools/picker_tool.h b/pcbnew/tools/picker_tool.h |
1716 | index 75f5571..60b5b6f 100644 |
1717 | --- a/pcbnew/tools/picker_tool.h |
1718 | +++ b/pcbnew/tools/picker_tool.h |
1719 | @@ -25,21 +25,20 @@ |
1720 | #ifndef PICKER_TOOL_H |
1721 | #define PICKER_TOOL_H |
1722 | |
1723 | -#include <tool/tool_interactive.h> |
1724 | #include <boost/optional/optional.hpp> |
1725 | -#include <boost/function.hpp> |
1726 | |
1727 | +#include "pcb_tool.h" |
1728 | /** |
1729 | * @brief Generic tool for picking a point. |
1730 | */ |
1731 | -class PICKER_TOOL : public TOOL_INTERACTIVE |
1732 | +class PICKER_TOOL : public PCB_TOOL |
1733 | { |
1734 | public: |
1735 | PICKER_TOOL(); |
1736 | ~PICKER_TOOL() {} |
1737 | |
1738 | ///> Mouse event click handler type. |
1739 | - typedef boost::function<bool(const VECTOR2D&)> CLICK_HANDLER; |
1740 | + typedef std::function<bool(const VECTOR2D&)> CLICK_HANDLER; |
1741 | |
1742 | ///> @copydoc TOOL_INTERACTIVE::Reset() |
1743 | void Reset( RESET_REASON aReason ) override {} |
1744 | diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp |
1745 | index 4042925..1d4c636 100644 |
1746 | --- a/pcbnew/tools/selection_tool.cpp |
1747 | +++ b/pcbnew/tools/selection_tool.cpp |
1748 | @@ -58,6 +58,8 @@ using namespace std::placeholders; |
1749 | #include "pcb_bright_box.h" |
1750 | #include "pcb_actions.h" |
1751 | |
1752 | +#include "kicad_plugin.h" |
1753 | + |
1754 | // Selection tool actions |
1755 | TOOL_ACTION PCB_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection", |
1756 | AS_GLOBAL, 0, |
1757 | @@ -120,8 +122,6 @@ TOOL_ACTION PCB_ACTIONS::filterSelection( "pcbnew.InteractiveSelection.FilterSel |
1758 | _( "Filter Selection" ), _( "Filter the types of items in the selection" ), |
1759 | nullptr ); |
1760 | |
1761 | - |
1762 | - |
1763 | class SELECT_MENU: public CONTEXT_MENU |
1764 | { |
1765 | public: |
1766 | @@ -609,11 +609,13 @@ void SELECTION_TOOL::setTransitions() |
1767 | Go( &SELECTION_TOOL::selectCopper, PCB_ACTIONS::selectCopper.MakeEvent() ); |
1768 | Go( &SELECTION_TOOL::selectNet, PCB_ACTIONS::selectNet.MakeEvent() ); |
1769 | Go( &SELECTION_TOOL::selectSameSheet, PCB_ACTIONS::selectSameSheet.MakeEvent() ); |
1770 | + |
1771 | Go( &SELECTION_TOOL::selectOnSheetFromEeschema, PCB_ACTIONS::selectOnSheetFromEeschema.MakeEvent() ); |
1772 | Go( &SELECTION_TOOL::updateSelection, PCB_ACTIONS::selectionModified.MakeEvent() ); |
1773 | } |
1774 | |
1775 | |
1776 | + |
1777 | SELECTION_LOCK_FLAGS SELECTION_TOOL::CheckLock() |
1778 | { |
1779 | if( !m_locked || m_editModules ) |
Kristoffer,
Please do not put license text inside Doxygen comments. I also saw
quite a few coding policy violations:
Trailing white space.
Missing spaces around function argument braces.
100 character line length exceeded.
Only one empty space (should be 2) between method definitions in .cpp
source files.
Curly bracket not on next line.
Incorrect indentation level.
Please clean these up before we merge your patch.
Thanks,
Wayne
On 9/26/2017 1:58 PM, Kristoffer wrote: odmark/ kicad:tom- copypasta into kicad:master. /code.launchpad .net/~kristoffe r-odmark/ kicad/+ git/kicad/ +merge/ 331369
> Kristoffer has proposed merging ~kristoffer-
>
> Requested reviews:
> Tomasz Wlostowski (twlostow)
>
> For more details, see:
> https:/
>
> Added copy-paste functionality to pcbnew. Coworked with Tomasz. I think it is fully acceptable in the current state and ready for mainstream testing.
>
>