KiCad PCB EDA Suite
Loading...
Searching...
No Matches
edit_table_tool_base.h
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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#ifndef EDIT_TABLE_TOOL_BASE_H
25#define EDIT_TABLE_TOOL_BASE_H
26
27#include <tool/tool_base.h>
28#include <tool/selection.h>
29#include <tool/actions.h>
30#include <wx/translation.h>
31
32class BASE_SCREEN;
33
34
39
40
41template<typename T_TABLE, typename T_TABLECELL, typename T_COMMIT>
43{
44protected:
45 void addMenus( CONDITIONAL_MENU& selToolMenu )
46 {
47 auto cellSelection = SELECTION_CONDITIONS::MoreThan( 0 )
50
51 auto cellBlockSelection = []( const SELECTION& sel )
52 {
53 if( sel.Size() < 2 )
54 return false;
55
56 int colMin = std::numeric_limits<int>::max();
57 int colMax = 0;
58 int rowMin = std::numeric_limits<int>::max();
59 int rowMax = 0;
60 int selectedArea = 0;
61
62 for( EDA_ITEM* item : sel )
63 {
64 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
65 {
66 colMin = std::min( colMin, cell->GetColumn() );
67 colMax = std::max( colMax, cell->GetColumn() + cell->GetColSpan() );
68 rowMin = std::min( rowMin, cell->GetRow() );
69 rowMax = std::max( rowMax, cell->GetRow() + cell->GetRowSpan() );
70
71 selectedArea += cell->GetColSpan() * cell->GetRowSpan();
72 }
73 }
74
75 return selectedArea == ( colMax - colMin ) * ( rowMax - rowMin );
76 };
77
78 auto mergedCellsSelection = []( const SELECTION& sel )
79 {
80 for( EDA_ITEM* item : sel )
81 {
82 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
83 {
84 if( cell->GetColSpan() > 1 || cell->GetRowSpan() > 1 )
85 return true;
86 }
87 }
88
89 return false;
90 };
91
92 //
93 // Add editing actions to the selection tool menu
94 //
95 selToolMenu.AddSeparator( 100 );
96 selToolMenu.AddItem( ACTIONS::addRowAbove, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
97 selToolMenu.AddItem( ACTIONS::addRowBelow, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
98 selToolMenu.AddItem( ACTIONS::addColBefore, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
99 selToolMenu.AddItem( ACTIONS::addColAfter, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
100
101 selToolMenu.AddSeparator( 100 );
102 selToolMenu.AddItem( ACTIONS::deleteRows, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
103 selToolMenu.AddItem( ACTIONS::deleteColumns, cellSelection && SELECTION_CONDITIONS::Idle,
104 100 );
105
106 selToolMenu.AddSeparator( 100 );
107 selToolMenu.AddItem( ACTIONS::mergeCells, cellSelection && cellBlockSelection, 100 );
108 selToolMenu.AddItem( ACTIONS::unmergeCells, cellSelection && mergedCellsSelection, 100 );
109
110 selToolMenu.AddSeparator( 100 );
111 selToolMenu.AddItem( ACTIONS::editTable, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
112
113 selToolMenu.AddSeparator( 100 );
114 }
115
116 int doAddRowAbove( const TOOL_EVENT& aEvent )
117 {
118 const SELECTION& selection = getTableCellSelection();
119 T_TABLECELL* topmost = nullptr;
120
121 for( EDA_ITEM* item : selection )
122 {
123 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
124
125 if( !topmost || cell->GetRow() < topmost->GetRow() )
126 topmost = cell;
127 }
128
129 if( !topmost )
130 return 0;
131
132 int row = topmost->GetRow();
133 T_TABLE* table = static_cast<T_TABLE*>( topmost->GetParent() );
134 T_COMMIT commit( getToolMgr() );
135 VECTOR2I pos = table->GetPosition();
136
137 // Make a copy of the source row before things start moving around
138 std::vector<T_TABLECELL*> sources;
139 sources.reserve( table->GetColCount() );
140
141 for( int col = 0; col < table->GetColCount(); ++col )
142 sources.push_back( table->GetCell( row, col ) );
143
144 commit.Modify( table, getScreen() );
145
146 for( int col = 0; col < table->GetColCount(); ++col )
147 {
148 T_TABLECELL* cell = copyCell( sources[col] );
149 table->InsertCell( row * table->GetColCount(), cell );
150 }
151
152 for( int afterRow = table->GetRowCount() - 1; afterRow > row; afterRow-- )
153 table->SetRowHeight( afterRow, table->GetRowHeight( afterRow - 1 ) );
154
155 table->SetPosition( pos );
156 table->Normalize();
157
159
160 commit.Push( _( "Add Row Above" ) );
161
162 return 0;
163 }
164
165 int doAddRowBelow( const TOOL_EVENT& aEvent )
166 {
167 const SELECTION& selection = getTableCellSelection();
168 T_TABLECELL* bottommost = nullptr;
169
170 if( selection.Empty() )
171 return 0;
172
173 for( EDA_ITEM* item : selection )
174 {
175 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
176
177 if( !bottommost || cell->GetRow() > bottommost->GetRow() )
178 bottommost = cell;
179 }
180
181 if( !bottommost )
182 return 0;
183
184 int row = bottommost->GetRow();
185 T_TABLE* table = static_cast<T_TABLE*>( bottommost->GetParent() );
186 T_COMMIT commit( getToolMgr() );
187 VECTOR2I pos = table->GetPosition();
188
189 // Make a copy of the source row before things start moving around
190 std::vector<T_TABLECELL*> sources;
191 sources.reserve( table->GetColCount() );
192
193 for( int col = 0; col < table->GetColCount(); ++col )
194 sources.push_back( table->GetCell( row, col ) );
195
196 commit.Modify( table, getScreen() );
197
198 for( int col = 0; col < table->GetColCount(); ++col )
199 {
200 T_TABLECELL* cell = copyCell( sources[col] );
201 table->InsertCell( ( row + 1 ) * table->GetColCount(), cell );
202 }
203
204 for( int afterRow = table->GetRowCount() - 1; afterRow > row; afterRow-- )
205 table->SetRowHeight( afterRow, table->GetRowHeight( afterRow - 1 ) );
206
207 table->SetPosition( pos );
208 table->Normalize();
209
211
212 commit.Push( _( "Add Row Below" ) );
213
214 return 0;
215 }
216
217 int doAddColumnBefore( const TOOL_EVENT& aEvent )
218 {
219 const SELECTION& selection = getTableCellSelection();
220 T_TABLECELL* leftmost = nullptr;
221
222 for( EDA_ITEM* item : selection )
223 {
224 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
225
226 if( !leftmost || cell->GetColumn() < leftmost->GetColumn() )
227 leftmost = cell;
228 }
229
230 if( !leftmost )
231 return 0;
232
233 int col = leftmost->GetColumn();
234 T_TABLE* table = static_cast<T_TABLE*>( leftmost->GetParent() );
235 int rowCount = table->GetRowCount();
236 T_COMMIT commit( getToolMgr() );
237 VECTOR2I pos = table->GetPosition();
238
239 // Make a copy of the source column before things start moving around
240 std::vector<T_TABLECELL*> sources;
241 sources.reserve( rowCount );
242
243 for( int row = 0; row < rowCount; ++row )
244 sources.push_back( table->GetCell( row, col ) );
245
246 commit.Modify( table, getScreen() );
247 table->SetColCount( table->GetColCount() + 1 );
248
249 for( int row = 0; row < rowCount; ++row )
250 {
251 T_TABLECELL* cell = copyCell( sources[row] );
252 table->InsertCell( row * table->GetColCount() + col, cell );
253 }
254
255 for( int afterCol = table->GetColCount() - 1; afterCol > col; afterCol-- )
256 table->SetColWidth( afterCol, table->GetColWidth( afterCol - 1 ) );
257
258 table->SetPosition( pos );
259 table->Normalize();
260
262
263 commit.Push( _( "Add Column Before" ) );
264
265 return 0;
266 }
267
268 int doAddColumnAfter( const TOOL_EVENT& aEvent )
269 {
270 const SELECTION& selection = getTableCellSelection();
271 T_TABLECELL* rightmost = nullptr;
272
273 for( EDA_ITEM* item : selection )
274 {
275 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
276
277 if( !rightmost || cell->GetColumn() > rightmost->GetColumn() )
278 rightmost = cell;
279 }
280
281 if( !rightmost )
282 return 0;
283
284 int col = rightmost->GetColumn();
285 T_TABLE* table = static_cast<T_TABLE*>( rightmost->GetParent() );
286 int rowCount = table->GetRowCount();
287 T_COMMIT commit( getToolMgr() );
288 VECTOR2I pos = table->GetPosition();
289
290 // Make a copy of the source column before things start moving around
291 std::vector<T_TABLECELL*> sources;
292 sources.reserve( rowCount );
293
294 for( int row = 0; row < rowCount; ++row )
295 sources.push_back( table->GetCell( row, col ) );
296
297 commit.Modify( table, getScreen() );
298 table->SetColCount( table->GetColCount() + 1 );
299
300 for( int row = 0; row < rowCount; ++row )
301 {
302 T_TABLECELL* cell = copyCell( sources[row] );
303 table->InsertCell( row * table->GetColCount() + col + 1, cell );
304 }
305
306 for( int afterCol = table->GetColCount() - 1; afterCol > col; afterCol-- )
307 table->SetColWidth( afterCol, table->GetColWidth( afterCol - 1 ) );
308
309 table->SetPosition( pos );
310 table->Normalize();
311
313
314 commit.Push( _( "Add Column After" ) );
315
316 return 0;
317 }
318
319 int doDeleteRows( const TOOL_EVENT& aEvent )
320 {
321 const SELECTION& selection = getTableCellSelection();
322
323 if( selection.Empty() )
324 return 0;
325
326 T_TABLE* table = static_cast<T_TABLE*>( selection[0]->GetParent() );
327 std::vector<int> deleted;
328
329 for( T_TABLECELL* cell : table->GetCells() )
330 cell->ClearFlags( STRUCT_DELETED );
331
332 for( int row = 0; row < table->GetRowCount(); ++row )
333 {
334 bool deleteRow = false;
335
336 for( int col = 0; col < table->GetColCount(); ++col )
337 {
338 if( table->GetCell( row, col )->IsSelected() )
339 {
340 deleteRow = true;
341 break;
342 }
343 }
344
345 if( deleteRow )
346 {
347 for( int col = 0; col < table->GetColCount(); ++col )
348 table->GetCell( row, col )->SetFlags( STRUCT_DELETED );
349
350 deleted.push_back( row );
351 }
352 }
353
354 T_COMMIT commit( getToolMgr() );
355
356 if( deleted.size() == (unsigned) table->GetRowCount() )
357 {
358 commit.Remove( table, getScreen() );
359 }
360 else
361 {
362 commit.Modify( table, getScreen() );
363
364 VECTOR2I pos = table->GetPosition();
365
367 table->DeleteMarkedCells();
368
369 for( int row = 0; row < table->GetRowCount(); ++row )
370 {
371 int offset = 0;
372
373 for( int deletedRow : deleted )
374 {
375 if( deletedRow >= row )
376 offset++;
377 }
378
379 table->SetRowHeight( row, table->GetRowHeight( row + offset ) );
380 }
381
382 table->SetPosition( pos );
383 table->Normalize();
384
386 }
387
388 if( deleted.size() > 1 )
389 commit.Push( _( "Delete Rows" ) );
390 else
391 commit.Push( _( "Delete Row" ) );
392
393 return 0;
394 }
395
396 int doDeleteColumns( const TOOL_EVENT& aEvent )
397 {
398 const SELECTION& selection = getTableCellSelection();
399
400 if( selection.Empty() )
401 return 0;
402
403 T_TABLE* table = static_cast<T_TABLE*>( selection[0]->GetParent() );
404 std::vector<int> deleted;
405
406 for( T_TABLECELL* cell : table->GetCells() )
407 cell->ClearFlags( STRUCT_DELETED );
408
409 for( int col = 0; col < table->GetColCount(); ++col )
410 {
411 bool deleteColumn = false;
412
413 for( int row = 0; row < table->GetRowCount(); ++row )
414 {
415 if( table->GetCell( row, col )->IsSelected() )
416 {
417 deleteColumn = true;
418 break;
419 }
420 }
421
422 if( deleteColumn )
423 {
424 for( int row = 0; row < table->GetRowCount(); ++row )
425 table->GetCell( row, col )->SetFlags( STRUCT_DELETED );
426
427 deleted.push_back( col );
428 }
429 }
430
431 T_COMMIT commit( getToolMgr() );
432
433 if( deleted.size() == (unsigned) table->GetColCount() )
434 {
435 commit.Remove( table, getScreen() );
436 }
437 else
438 {
439 commit.Modify( table, getScreen() );
440
441 VECTOR2I pos = table->GetPosition();
442
444 table->DeleteMarkedCells();
445 table->SetColCount( table->GetColCount() - deleted.size() );
446
447 for( int col = 0; col < table->GetColCount(); ++col )
448 {
449 int offset = 0;
450
451 for( int deletedCol : deleted )
452 {
453 if( deletedCol >= col )
454 offset++;
455 }
456
457 table->SetColWidth( col, table->GetColWidth( col + offset ) );
458 }
459
460 table->SetPosition( pos );
461 table->Normalize();
462
464 }
465
466 if( deleted.size() > 1 )
467 commit.Push( _( "Delete Columns" ) );
468 else
469 commit.Push( _( "Delete Column" ) );
470
471 return 0;
472 }
473
474 int doMergeCells( const TOOL_EVENT& aEvent )
475 {
476 const SELECTION& sel = getTableCellSelection();
477
478 if( sel.Empty() )
479 return 0;
480
481 int colMin = std::numeric_limits<int>::max();
482 int colMax = 0;
483 int rowMin = std::numeric_limits<int>::max();
484 int rowMax = 0;
485
486 T_COMMIT commit( getToolMgr() );
487 T_TABLE* table = static_cast<T_TABLE*>( sel[0]->GetParent() );
488
489 for( EDA_ITEM* item : sel )
490 {
491 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
492 {
493 colMin = std::min( colMin, cell->GetColumn() );
494 colMax = std::max( colMax, cell->GetColumn() + cell->GetColSpan() );
495 rowMin = std::min( rowMin, cell->GetRow() );
496 rowMax = std::max( rowMax, cell->GetRow() + cell->GetRowSpan() );
497 }
498 }
499
500 wxString content;
501 VECTOR2I extents;
502
503 for( int row = rowMin; row < rowMax; ++row )
504 {
505 extents.y += table->GetRowHeight( row );
506 extents.x = 0;
507
508 for( int col = colMin; col < colMax; ++col )
509 {
510 extents.x += table->GetColWidth( col );
511
512 T_TABLECELL* cell = table->GetCell( row, col );
513
514 if( !cell->GetText().IsEmpty() )
515 {
516 if( !content.IsEmpty() )
517 content += "\n";
518
519 content += cell->GetText();
520 }
521
522 commit.Modify( cell, getScreen() );
523 cell->SetColSpan( 0 );
524 cell->SetRowSpan( 0 );
525 cell->SetText( wxEmptyString );
526 }
527 }
528
529 T_TABLECELL* topLeft = table->GetCell( rowMin, colMin );
530 topLeft->SetColSpan( colMax - colMin );
531 topLeft->SetRowSpan( rowMax - rowMin );
532 topLeft->SetText( content );
533 topLeft->SetEnd( topLeft->GetStart() + extents );
534
535 table->Normalize();
536 commit.Push( _( "Merge Cells" ) );
537
539
540 return 0;
541 }
542
543 int doUnmergeCells( const TOOL_EVENT& aEvent )
544 {
545 const SELECTION& sel = getTableCellSelection();
546
547 if( sel.Empty() )
548 return 0;
549
550 T_COMMIT commit( getToolMgr() );
551 T_TABLE* table = static_cast<T_TABLE*>( sel[0]->GetParent() );
552
553 for( EDA_ITEM* item : sel )
554 {
555 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
556 {
557 int rowSpan = cell->GetRowSpan();
558 int colSpan = cell->GetColSpan();
559
560 for( int row = cell->GetRow(); row < cell->GetRow() + rowSpan; ++row )
561 {
562 for( int col = cell->GetColumn(); col < cell->GetColumn() + colSpan; ++col )
563 {
564 T_TABLECELL* target = table->GetCell( row, col );
565 commit.Modify( target, getScreen() );
566 target->SetColSpan( 1 );
567 target->SetRowSpan( 1 );
568
569 VECTOR2I extents( table->GetColWidth( col ), table->GetRowHeight( row ) );
570 target->SetEnd( target->GetStart() + extents );
571 }
572 }
573 }
574 }
575
576 table->Normalize();
577 commit.Push( _( "Unmerge Cells" ) );
578
580
581 return 0;
582 }
583
584 virtual TOOL_MANAGER* getToolMgr() = 0;
585 virtual BASE_SCREEN* getScreen() = 0;
586
587 virtual const SELECTION& getTableCellSelection() = 0;
588 virtual void clearSelection() = 0;
589
590 virtual T_TABLECELL* copyCell( T_TABLECELL* aSource ) = 0;
591};
592
593#endif //EDIT_TABLE_TOOL_BASE_H
static TOOL_ACTION addRowAbove
Definition actions.h:104
static TOOL_ACTION addColBefore
Definition actions.h:106
static TOOL_ACTION deleteRows
Definition actions.h:108
static TOOL_ACTION addRowBelow
Definition actions.h:105
static TOOL_ACTION deleteColumns
Definition actions.h:109
static TOOL_ACTION unmergeCells
Definition actions.h:111
static TOOL_ACTION mergeCells
Definition actions.h:110
static TOOL_ACTION addColAfter
Definition actions.h:107
static TOOL_ACTION editTable
Definition actions.h:112
Handles how to draw a screen (a board, a schematic ...)
Definition base_screen.h:41
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
SCH_TABLE_EDIT_TOOL and PCB_TABLE_EDIT_TOOL share most of their algorithms, which are implemented her...
virtual TOOL_MANAGER * getToolMgr()=0
int doDeleteColumns(const TOOL_EVENT &aEvent)
int doAddColumnAfter(const TOOL_EVENT &aEvent)
int doAddRowBelow(const TOOL_EVENT &aEvent)
int doAddColumnBefore(const TOOL_EVENT &aEvent)
int doAddRowAbove(const TOOL_EVENT &aEvent)
int doMergeCells(const TOOL_EVENT &aEvent)
virtual const SELECTION & getTableCellSelection()=0
virtual BASE_SCREEN * getScreen()=0
int doDeleteRows(const TOOL_EVENT &aEvent)
virtual T_TABLECELL * copyCell(T_TABLECELL *aSource)=0
void addMenus(CONDITIONAL_MENU &selToolMenu)
virtual void clearSelection()=0
int doUnmergeCells(const TOOL_EVENT &aEvent)
static const TOOL_EVENT SelectedEvent
Definition actions.h:346
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
Generic, UI-independent tool event.
Definition tool_event.h:171
Master controller class:
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
#define _(s)
#define STRUCT_DELETED
flag indication structures to be erased
@ SCH_TABLECELL_T
Definition typeinfo.h:168
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:95
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695