KiCad PCB EDA Suite
Loading...
Searching...
No Matches
vertex_editor_pane.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "vertex_editor_pane.h"
21
22#include <limits>
23
24#include <wx/aui/aui.h>
25#include <wx/grid.h>
26#include <wx/settings.h>
27#include <wx/sizer.h>
28#include <wx/translation.h>
29
30#include <board_item.h>
32#include <eda_units.h>
33#include <pcb_base_edit_frame.h>
34#include <pcb_shape.h>
35#include <tool/edit_points.h>
37#include <tool/tool_manager.h>
38#include <tool/actions.h>
39#include <zone.h>
40
41#include <view/view.h>
42
44 wxPanel( aFrame ),
45 m_frame( aFrame ),
46 m_item( nullptr ),
47 m_zone( nullptr ),
48 m_shape( nullptr ),
49 m_grid( nullptr ),
50 m_updatingGrid( false )
51{
52 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
53 m_grid = new wxGrid( this, wxID_ANY );
54 m_grid->CreateGrid( 0, 2 );
55 m_grid->SetRowLabelSize( 0 );
56 m_grid->SetColLabelValue( 0, _( "X coord" ) );
57 m_grid->SetColLabelValue( 1, _( "Y coord" ) );
58 m_grid->EnableDragGridSize( false );
59 m_grid->EnableDragRowSize( false );
60 m_grid->EnableDragColSize( false );
61 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
62 m_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
63 m_grid->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_ALWAYS );
64 m_grid->EnableScrolling( false, true );
65 m_grid->SetColMinimalWidth( 0, FromDIP( 120 ) );
66 m_grid->SetColMinimalWidth( 1, FromDIP( 120 ) );
67
68 topSizer->Add( m_grid, 1, wxEXPAND | wxALL, FromDIP( 5 ) );
69
70 SetSizer( topSizer );
71
72 Bind( wxEVT_SIZE, &PCB_VERTEX_EDITOR_PANE::OnSize, this );
73 m_grid->Bind( wxEVT_GRID_CELL_CHANGED, &PCB_VERTEX_EDITOR_PANE::OnGridCellChange, this );
74 m_grid->Bind( wxEVT_GRID_SELECT_CELL, &PCB_VERTEX_EDITOR_PANE::OnGridSelectCell, this );
75
76 // Initial column sizing
78}
79
81{
82 if( m_frame )
83 m_frame->OnVertexEditorPaneClosed( this );
84}
85
86
88{
89 m_item = aItem;
90 m_zone = dynamic_cast<ZONE*>( aItem );
91 m_shape = dynamic_cast<PCB_SHAPE*>( aItem );
92
94
95 if( m_grid->GetNumberRows() > 0 )
96 {
97 m_grid->SetGridCursor( 0, 0 );
98 m_grid->SelectRow( 0 );
99 updateHighlight( 0 );
100 }
101
103}
104
105
107{
108 m_item = nullptr;
109 m_zone = nullptr;
110 m_shape = nullptr;
111
112 m_updatingGrid = true;
113 if( m_grid->GetNumberRows() > 0 )
114 m_grid->DeleteRows( 0, m_grid->GetNumberRows() );
115 m_rows.clear();
116 m_updatingGrid = false;
117}
118
119
121{
122 // Check if the new item is a polygon or zone
123 if( aNewItem )
124 {
125 ZONE* zone = dynamic_cast<ZONE*>( aNewItem );
126 PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aNewItem );
127
128 bool isPolygon = ( zone != nullptr ) || ( shape && shape->GetShape() == SHAPE_T::POLY );
129
130 if( isPolygon )
131 {
132 // Update to the new item
133 SetItem( aNewItem );
134 }
135 else
136 {
137 // Not a polygon/zone, clear the editor
138 ClearItem();
139 }
140 }
141 else
142 {
143 // Nothing selected, clear the editor
144 ClearItem();
145 }
146}
147
149{
150 m_updatingGrid = true;
151
152 if( m_grid->GetNumberRows() > 0 )
153 m_grid->DeleteRows( 0, m_grid->GetNumberRows() );
154
155 m_rows.clear();
156
157 SHAPE_POLY_SET* poly = getPoly();
158
159 if( poly )
160 {
161 for( auto it = poly->CIterateWithHoles(); it; ++it )
162 {
163 m_rows.push_back( it.GetIndex() );
164 m_grid->AppendRows( 1 );
165 updateRow( m_grid->GetNumberRows() - 1 );
166 }
167 }
168
169 m_updatingGrid = false;
170}
171
173{
174 if( aRow < 0 || aRow >= m_grid->GetNumberRows() )
175 return;
176
177 SHAPE_POLY_SET* poly = getPoly();
178
179 if( !poly || aRow >= (int) m_rows.size() )
180 return;
181
182 const SHAPE_POLY_SET::VERTEX_INDEX& idx = m_rows[aRow];
183 VECTOR2I vertex = poly->CVertex( idx );
184
185 m_updatingGrid = true;
186 m_grid->SetCellValue( aRow, 0, formatCoord( vertex.x, ORIGIN_TRANSFORMS::ABS_X_COORD ) );
187 m_grid->SetCellValue( aRow, 1, formatCoord( vertex.y, ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
188 m_updatingGrid = false;
189}
190
192{
193 // Highlighting is now handled by the point editor tool
194 // We just refresh the view
195 if( m_frame && m_frame->GetCanvas() )
196 {
197 m_frame->GetCanvas()->GetView()->Update( m_item );
198 m_frame->GetCanvas()->Refresh();
199 }
200}
201
202
204{
205 if( m_zone )
206 {
207 m_zone->UnFill();
208 m_zone->SetNeedRefill( true );
209 m_zone->HatchBorder();
210 }
211
212 if( m_frame && m_frame->GetCanvas() )
213 {
214 m_frame->GetCanvas()->GetView()->Update( m_item );
215 m_frame->GetCanvas()->Refresh();
216 }
217}
218
219bool PCB_VERTEX_EDITOR_PANE::parseCellValue( const wxString& aText,
221 int& aResult ) const
222{
223 long long displayValue = EDA_UNIT_UTILS::UI::ValueFromString( pcbIUScale, m_frame->GetUserUnits(), aText );
224
225 if( !displayValue )
226 return false;
227
228 long long internal = m_frame->GetOriginTransforms().FromDisplay( displayValue, aCoordType );
229
230 if( internal < std::numeric_limits<int>::min() || internal > std::numeric_limits<int>::max() )
231 return false;
232
233 aResult = static_cast<int>( internal );
234 return true;
235}
236
238 ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType ) const
239{
240 int displayValue = m_frame->GetOriginTransforms().ToDisplay( aValue, aCoordType );
241 return m_frame->MessageTextFromValue( displayValue );
242}
243
245{
246 if( m_zone )
247 return m_zone->Outline();
248
249 if( m_shape && m_shape->GetShape() == SHAPE_T::POLY )
250 return &m_shape->GetPolyShape();
251
252 return nullptr;
253}
254
256{
257 if( m_zone )
258 return m_zone->Outline();
259
260 if( m_shape && m_shape->GetShape() == SHAPE_T::POLY )
261 return &m_shape->GetPolyShape();
262
263 return nullptr;
264}
265
266
268{
269 if( m_updatingGrid )
270 return;
271
272 int row = aEvent.GetRow();
273 int col = aEvent.GetCol();
274
275 if( row < 0 || row >= (int) m_rows.size() )
276 {
277 updateHighlight( -1 );
278 return;
279 }
280
281 SHAPE_POLY_SET* poly = getPoly();
282
283 if( !poly || !m_item )
284 return;
285
286 const SHAPE_POLY_SET::VERTEX_INDEX& idx = m_rows[row];
287 VECTOR2I vertex = poly->CVertex( idx );
288 int newValue;
289
292
293 if( !parseCellValue( m_grid->GetCellValue( row, col ), coordType, newValue ) )
294 {
295 updateRow( row );
296 return;
297 }
298
299 int& target = ( col == 0 ) ? vertex.x : vertex.y;
300
301 if( target == newValue )
302 {
303 updateRow( row );
304 return;
305 }
306
307 // Create a new commit for each edit
308 BOARD_COMMIT commit( m_frame );
309 commit.Modify( m_item );
310
311 target = newValue;
312 poly->SetVertex( idx, vertex );
313
314 if( m_zone )
315 {
316 m_zone->UnFill();
317 m_zone->SetNeedRefill( true );
318 m_zone->HatchBorder();
319 }
320
321 commit.Push( _( "Edit Vertex" ) );
322
323 // Update the view after the commit
324 if( m_frame && m_frame->GetCanvas() )
325 {
326 m_frame->GetCanvas()->GetView()->Update( m_item );
327 m_frame->GetCanvas()->Refresh();
328 }
329
330 updateRow( row );
331 updateHighlight( row );
332}
333
335{
336 updateHighlight( aEvent.GetRow() );
337 aEvent.Skip();
338}
339
340
342{
343 if( !m_grid || m_grid->GetNumberCols() != 2 )
344 return;
345
346 // Get the available width (excluding row labels and scrollbar)
347 int width = m_grid->GetClientSize().GetWidth() - m_grid->GetRowLabelSize();
348
349 // Reserve space for vertical scrollbar if it's shown
350 if( m_grid->GetScrollRange( wxVERTICAL ) > 0 )
351 width -= wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
352
353 // Split the width equally between the two columns
354 int colWidth = width / 2;
355
356 if( colWidth > m_grid->GetColMinimalAcceptableWidth() )
357 {
358 m_grid->SetColSize( 0, colWidth );
359 m_grid->SetColSize( 1, colWidth );
360 }
361}
362
363
364void PCB_VERTEX_EDITOR_PANE::OnSize( wxSizeEvent& aEvent )
365{
367 aEvent.Skip();
368}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
SHAPE_T GetShape() const
Definition eda_shape.h:168
COORD_TYPES_T
The supported Display Origin Transform types.
Common, abstract interface for edit frames.
void SetItem(BOARD_ITEM *aItem)
PCB_BASE_EDIT_FRAME * m_frame
void OnGridSelectCell(wxGridEvent &aEvent)
void OnSize(wxSizeEvent &aEvent)
std::vector< SHAPE_POLY_SET::VERTEX_INDEX > m_rows
wxString formatCoord(int aValue, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType) const
void OnSelectionChanged(BOARD_ITEM *aNewItem)
Update the pane in response to external selection changes.
PCB_VERTEX_EDITOR_PANE(PCB_BASE_EDIT_FRAME *aFrame)
bool parseCellValue(const wxString &aText, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType, int &aResult) const
void OnGridCellChange(wxGridEvent &aEvent)
Represent a set of closed polygons.
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
CONST_ITERATOR CIterateWithHoles(int aOutline) const
Handle a list of polygons defining a copper zone.
Definition zone.h:74
#define _(s)
KICOMMON_API long long int ValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue in aUnits to internal units used by the application.
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695