KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_tablecell.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
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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <advanced_config.h>
21#include <common.h>
22#include <sch_edit_frame.h>
23#include <widgets/msgpanel.h>
24#include <string_utils.h>
25#include <sch_table.h>
26#include <sch_tablecell.h>
27#include <properties/property.h>
29
30
31SCH_TABLECELL::SCH_TABLECELL( int aLineWidth, FILL_T aFillType ) :
32 SCH_TEXTBOX( LAYER_NOTES, aLineWidth, aFillType, wxEmptyString, SCH_TABLECELL_T ),
33 m_colSpan( 1 ),
34 m_rowSpan( 1 )
35{
36}
37
38
40{
41 SCH_TEXTBOX::swapData( aItem );
42
43 SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( aItem );
44
45 std::swap( m_colSpan, cell->m_colSpan );
46 std::swap( m_rowSpan, cell->m_rowSpan );
47}
48
49
50wxString SCH_TABLECELL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
51{
52 return wxString::Format( _( "Table Cell %s" ), GetAddr() );
53}
54
55
57{
58 const SCH_TABLE* table = static_cast<const SCH_TABLE*>( GetParent() );
59
60 for( int row = 0; row < table->GetRowCount(); ++row )
61 {
62 for( int col = 0; col < table->GetColCount(); ++col )
63 {
64 if( table->GetCell( row, col ) == this )
65 return row;
66 }
67 }
68
69 return -1;
70}
71
72
74{
75 const SCH_TABLE* table = static_cast<const SCH_TABLE*>( GetParent() );
76
77 for( int row = 0; row < table->GetRowCount(); ++row )
78 {
79 for( int col = 0; col < table->GetColCount(); ++col )
80 {
81 if( table->GetCell( row, col ) == this )
82 return col;
83 }
84 }
85
86 return -1;
87}
88
89
90wxString SCH_TABLECELL::GetAddr() const
91{
92 return wxString::Format( wxT( "%c%d" ), 'A' + GetColumn() % 26, GetRow() );
93}
94
95
106static bool parseCellAddress( const wxString& aAddr, int& aRow, int& aCol )
107{
108 if( aAddr.IsEmpty() )
109 return false;
110
111 // Extract column part (letters) and row part (numbers)
112 size_t i = 0;
113 wxString colPart;
114
115 // Read column letters (A-Z, AA-ZZ, etc.)
116 while( i < aAddr.Length() && wxIsalpha( aAddr[i] ) )
117 {
118 colPart += wxToupper( aAddr[i] );
119 i++;
120 }
121
122 // Must have at least one letter
123 if( colPart.IsEmpty() )
124 return false;
125
126 // Convert column letters to 0-based index (A=0, B=1, ..., Z=25, AA=26, AB=27, etc.)
127 aCol = 0;
128 for( size_t j = 0; j < colPart.Length(); j++ )
129 {
130 aCol = aCol * 26 + ( colPart[j] - 'A' + 1 );
131 }
132 aCol -= 1; // Convert to 0-based
133
134 // Read row number (0-based)
135 wxString rowPart = aAddr.Mid( i );
136 if( rowPart.IsEmpty() )
137 return false;
138
139 // Convert row string to number (already 0-based in address string)
140 long rowNum;
141 if( !rowPart.ToLong( &rowNum ) || rowNum < 0 )
142 return false;
143
144 aRow = rowNum; // Already 0-based
145
146 return true;
147}
148
149
150wxString SCH_TABLECELL::GetShownText( const RENDER_SETTINGS* aSettings, const SCH_SHEET_PATH* aPath,
151 bool aAllowExtraText, int aDepth ) const
152{
153 // Local depth counter for ResolveTextVars iteration tracking (separate from cross-cell aDepth)
154 int depth = 0;
155
156 SCH_SHEET* sheet = nullptr;
157
158 if( aPath )
159 sheet = aPath->Last();
160
161 // Text variable resolver supporting:
162 // - ${ROW}, ${COL}, ${ADDR} - cell position variables
163 // - @{expression} - math expression evaluation
164 // - ${CELL("A1")} or ${CELL(row,col)} - reference to another cell's evaluated text
165 // - \${...} and \@{...} - escape sequences for literal display
166 std::function<bool( wxString* )> tableCellResolver =
167 [&]( wxString* token ) -> bool
168 {
169 if( token->IsSameAs( wxT( "ROW" ) ) )
170 {
171 *token = wxString::Format( wxT( "%d" ), GetRow() ); // 0-based
172 return true;
173 }
174 else if( token->IsSameAs( wxT( "COL" ) ) )
175 {
176 *token = wxString::Format( wxT( "%d" ), GetColumn() ); // 0-based
177 return true;
178 }
179 else if( token->IsSameAs( wxT( "ADDR" ) ) )
180 {
181 *token = GetAddr();
182 return true;
183 }
184 else if( token->StartsWith( wxT( "CELL(" ) ) && token->EndsWith( wxT( ")" ) ) )
185 {
186 // Handle CELL("A0") or CELL(0, 1) syntax
187 wxString args = token->Mid( 5, token->Length() - 6 ); // Extract arguments
188 args.Trim( true ).Trim( false ); // Remove whitespace
189
190 SCH_TABLE* table = static_cast<SCH_TABLE*>( GetParent() );
191 if( !table )
192 {
193 *token = wxT( "<Unresolved: CELL() requires table context>" );
194 return true;
195 }
196
197 int targetRow = -1;
198 int targetCol = -1;
199
200 // Check if it's cell("A1") format (string argument with quotes)
201 if( args.StartsWith( wxT( "\"" ) ) && args.EndsWith( wxT( "\"" ) ) )
202 {
203 wxString addr = args.Mid( 1, args.Length() - 2 ); // Remove quotes
204 if( !parseCellAddress( addr, targetRow, targetCol ) )
205 {
206 *token = wxString::Format( wxT( "<Unresolved: Invalid cell address: %s>" ), addr );
207 return true;
208 }
209 }
210 // Check if it's cell(row, col) format (two numeric arguments)
211 else if( args.Find( ',' ) != wxNOT_FOUND )
212 {
213 wxString rowStr = args.BeforeFirst( ',' ).Trim( true ).Trim( false );
214 wxString colStr = args.AfterFirst( ',' ).Trim( true ).Trim( false );
215
216 long rowNum, colNum;
217 if( !rowStr.ToLong( &rowNum ) || !colStr.ToLong( &colNum ) )
218 {
219 *token = wxString::Format( wxT( "<Unresolved: Invalid cell coordinates: %s>" ), args );
220 return true;
221 }
222
223 // Arguments are already 0-based
224 targetRow = rowNum;
225 targetCol = colNum;
226 }
227 else
228 {
229 *token = wxString::Format( wxT( "<Unresolved: Invalid CELL() syntax: %s>" ), args );
230 return true;
231 }
232
233 // Check bounds
234 if( targetRow < 0 || targetRow >= table->GetRowCount() || targetCol < 0
235 || targetCol >= table->GetColCount() )
236 {
237 wxString cellAddr;
238 if( targetRow >= 0 && targetCol >= 0 )
239 {
240 char colLetter = 'A' + ( targetCol % 26 );
241 cellAddr = wxString::Format( wxT( "%c%d" ), colLetter, targetRow );
242 }
243 else
244 {
245 cellAddr = args;
246 }
247 *token = wxString::Format( wxT( "<Unresolved: Cell %s not found>" ), cellAddr );
248 return true;
249 }
250
251 // Get the target cell and return its evaluated text
252 SCH_TABLECELL* targetCell = table->GetCell( targetRow, targetCol );
253 if( targetCell )
254 {
255 // Check for excessive recursion depth (circular references)
257 if( aDepth >= maxDepth )
258 {
259 *token = wxT( "<Circular reference>" );
260 return true;
261 }
262
263 *token = targetCell->GetShownText( aSettings, aPath, aAllowExtraText, aDepth + 1 );
264 return true;
265 }
266 else
267 {
268 *token = wxT( "<Unresolved: Cell not found>" );
269 return true;
270 }
271 }
272
273 // Fall back to sheet variables
274 if( sheet )
275 {
276 if( sheet->ResolveTextVar( aPath, token, depth + 1 ) )
277 return true;
278 }
279
280 return false;
281 };
282
283 wxString text = EDA_TEXT::GetShownText( aAllowExtraText, depth );
284
285 if( HasTextVars() )
286 text = ResolveTextVars( text, &tableCellResolver, depth );
287
288 VECTOR2I size = GetEnd() - GetStart();
289 int colWidth;
290
291 if( GetTextAngle().IsVertical() )
292 colWidth = abs( size.y ) - ( GetMarginTop() + GetMarginBottom() );
293 else
294 colWidth = abs( size.x ) - ( GetMarginLeft() + GetMarginRight() );
295
296 GetDrawFont( aSettings )
298
299 // Convert escape markers back to literal ${} and @{} for final display
300 // Only do this at the top level (aDepth == 0) to avoid premature unescaping in nested CELL() calls
301 if( aDepth == 0 )
302 {
303 text.Replace( wxT( "<<<ESC_DOLLAR:" ), wxT( "${" ) );
304 text.Replace( wxT( "<<<ESC_AT:" ), wxT( "@{" ) );
305 }
306
307 return text;
308}
309
310
312{
313 return static_cast<SCH_TABLE*>( GetParent() )->GetColWidth( GetColumn() );
314}
315
316
318{
319 SCH_TABLE* table = static_cast<SCH_TABLE*>( GetParent() );
320
321 table->SetColWidth( GetColumn(), aWidth );
322 table->Normalize();
323}
324
325
327{
328 return static_cast<SCH_TABLE*>( GetParent() )->GetRowHeight( GetRow() );
329}
330
331
333{
334 SCH_TABLE* table = static_cast<SCH_TABLE*>( GetParent() );
335
336 table->SetRowHeight( GetRow(), aHeight );
337 table->Normalize();
338}
339
340
341void SCH_TABLECELL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit,
342 int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
343{
344 const int cell_body_style = -1; // flag to disable box ouline plotting
345
346 if( m_colSpan >= 1 && m_rowSpan >= 1 )
347 SCH_TEXTBOX::Plot( aPlotter, aBackground, aPlotOpts, aUnit, cell_body_style, aOffset, aDimmed );
348}
349
350
351void SCH_TABLECELL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
352{
353 aList.emplace_back( _( "Table Cell" ), GetAddr() );
354
355 // Don't use GetShownText() here; we want to show the user the variable references
356 aList.emplace_back( _( "Text" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
357
358 aList.emplace_back( _( "Cell Width" ), aFrame->MessageTextFromValue( std::abs( GetEnd().x - GetStart().x ) ) );
359 aList.emplace_back( _( "Cell Height" ), aFrame->MessageTextFromValue( std::abs( GetEnd().y - GetStart().y ) ) );
360
361 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
362
363 wxString textStyle[] = { _( "Normal" ), _( "Italic" ), _( "Bold" ), _( "Bold Italic" ) };
364 int style = IsBold() && IsItalic() ? 3 : IsBold() ? 2 : IsItalic() ? 1 : 0;
365 aList.emplace_back( _( "Style" ), textStyle[style] );
366
367 aList.emplace_back( _( "Text Size" ), aFrame->MessageTextFromValue( GetTextWidth() ) );
368}
369
370
371double SCH_TABLECELL::Similarity( const SCH_ITEM& aOtherItem ) const
372{
373 if( aOtherItem.Type() != Type() )
374 return 0.0;
375
376 const SCH_TABLECELL& other = static_cast<const SCH_TABLECELL&>( aOtherItem );
377
378 double similarity = 1.0;
379
380 if( m_colSpan != other.m_colSpan )
381 similarity *= 0.9;
382
383 if( m_rowSpan != other.m_rowSpan )
384 similarity *= 0.9;
385
386 similarity *= SCH_TEXTBOX::Similarity( other );
387
388 return similarity;
389}
390
391
392bool SCH_TABLECELL::operator==( const SCH_ITEM& aOtherItem ) const
393{
394 if( aOtherItem.Type() != Type() )
395 return false;
396
397 const SCH_TABLECELL& other = static_cast<const SCH_TABLECELL&>( aOtherItem );
398
399 return *this == other;
400}
401
402
403bool SCH_TABLECELL::operator==( const SCH_TABLECELL& aOtherItem ) const
404{
405 return m_colSpan == aOtherItem.m_colSpan && m_rowSpan == aOtherItem.m_rowSpan
406 && SCH_TEXTBOX::operator==( aOtherItem );
407}
408
409
411{
413 {
416
425
426 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start X" ) );
427 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start Y" ) );
428 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "End X" ) );
429 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "End Y" ) );
430
431 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Shape" ) );
432 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Width" ) );
433 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Height" ) );
434 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Fill" ) );
435 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Fill Color" ) );
436 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Width" ) );
437 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Style" ) );
438 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Color" ) );
439 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Corner Radius" ) );
440
441 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
442 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
443 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Thickness" ) );
444 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
445 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Mirrored" ) );
446 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Visible" ) );
447 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Hyperlink" ) );
448
449 const wxString tableProps = _( "Table" );
450
454 tableProps );
455
459 tableProps );
460
461 const wxString cellProps = _( "Cell Properties" );
462
464 _HKI( "Background Fill" ), &EDA_SHAPE::SetFilled, &EDA_SHAPE::IsSolidFill ),
465 cellProps );
466
467 propMgr.AddProperty( new PROPERTY<SCH_TABLECELL, COLOR4D, EDA_SHAPE>( _HKI( "Background Fill Color" ),
470 cellProps )
472 }
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
The base class for create windows for drawing purpose.
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
EDA_ITEM * GetParent() const
Definition eda_item.h:110
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:152
void SetFillColor(const COLOR4D &aColor)
Definition eda_shape.h:170
bool IsSolidFill() const
Definition eda_shape.h:133
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
COLOR4D GetFillColor() const
Definition eda_shape.h:169
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:89
virtual VECTOR2I GetTextSize() const
Definition eda_text.h:282
bool IsItalic() const
Definition eda_text.h:190
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
KIFONT::FONT * GetFont() const
Definition eda_text.h:268
virtual int GetTextWidth() const
Definition eda_text.h:285
bool HasTextVars() const
Indicates the ShownText has text var references which need to be processed.
Definition eda_text.h:129
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:168
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:461
bool IsBold() const
Definition eda_text.h:205
virtual wxString GetShownText(bool aAllowExtraText, int aDepth=0) const
Return the string actually shown after processing of the base text.
Definition eda_text.h:121
void LinebreakText(wxString &aText, int aColumnWidth, const VECTOR2I &aGlyphSize, int aThickness, bool aBold, bool aItalic) const
Insert characters into text to ensure that no lines are wider than aColumnWidth.
Definition font.cpp:621
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
Base plotter engine class.
Definition plotter.h:133
PROPERTY_BASE & SetIsHiddenFromRulesEditor(bool aHide=true)
Definition property.h:326
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:52
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the sheet.
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
int GetRowHeight() const
void swapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
SCH_TABLECELL(int aLineWidth=0, FILL_T aFillType=FILL_T::NO_FILL)
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
wxString GetAddr() const
bool operator==(const SCH_TABLECELL &aOther) const
wxString GetShownText(const RENDER_SETTINGS *aSettings, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
void SetColumnWidth(int aWidth)
int GetColumn() const
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
void SetRowHeight(int aHeight)
int GetColumnWidth() const
int GetRow() const
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
int GetMarginBottom() const
Definition sch_textbox.h:72
bool operator==(const SCH_ITEM &aOther) const override
int GetMarginLeft() const
Definition sch_textbox.h:69
int GetMarginRight() const
Definition sch_textbox.h:71
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
int GetMarginTop() const
Definition sch_textbox.h:70
void swapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
KIFONT::FONT * GetDrawFont(const RENDER_SETTINGS *aSettings) const override
SCH_TEXTBOX(SCH_LAYER_ID aLayer=LAYER_NOTES, int aLineWidth=0, FILL_T aFillType=FILL_T::NO_FILL, const wxString &aText=wxEmptyString, KICAD_T aType=SCH_TEXTBOX_T)
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
Definition common.cpp:310
The common library.
#define _(s)
FILL_T
Definition eda_shape.h:59
int m_ResolveTextRecursionDepth
The number of recursions to resolve text variables.
@ LAYER_NOTES
Definition layer_ids.h:473
Message panel definition file.
KICOMMON_API wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
#define _HKI(x)
Definition page_info.cpp:40
#define TYPE_HASH(x)
Definition property.h:74
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
static struct SCH_TABLECELL_DESC _SCH_TABLECELL_DESC
static bool parseCellAddress(const wxString &aAddr, int &aRow, int &aCol)
Parse a cell address string like "A0" or "B12" into 0-based row and column indices.
@ SCH_TABLECELL_T
Definition typeinfo.h:163
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683