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 = [&]( wxString* token ) -> bool
167 {
168 if( token->IsSameAs( wxT( "ROW" ) ) )
169 {
170 *token = wxString::Format( wxT( "%d" ), GetRow() ); // 0-based
171 return true;
172 }
173 else if( token->IsSameAs( wxT( "COL" ) ) )
174 {
175 *token = wxString::Format( wxT( "%d" ), GetColumn() ); // 0-based
176 return true;
177 }
178 else if( token->IsSameAs( wxT( "ADDR" ) ) )
179 {
180 *token = GetAddr();
181 return true;
182 }
183 else if( token->StartsWith( wxT( "CELL(" ) ) && token->EndsWith( wxT( ")" ) ) )
184 {
185 // Handle CELL("A0") or CELL(0, 1) syntax
186 wxString args = token->Mid( 5, token->Length() - 6 ); // Extract arguments
187 args.Trim( true ).Trim( false ); // Remove whitespace
188
189 SCH_TABLE* table = static_cast<SCH_TABLE*>( GetParent() );
190 if( !table )
191 {
192 *token = wxT( "<Unresolved: CELL() requires table context>" );
193 return true;
194 }
195
196 int targetRow = -1;
197 int targetCol = -1;
198
199 // Check if it's cell("A1") format (string argument with quotes)
200 if( args.StartsWith( wxT( "\"" ) ) && args.EndsWith( wxT( "\"" ) ) )
201 {
202 wxString addr = args.Mid( 1, args.Length() - 2 ); // Remove quotes
203 if( !parseCellAddress( addr, targetRow, targetCol ) )
204 {
205 *token = wxString::Format( wxT( "<Unresolved: Invalid cell address: %s>" ), addr );
206 return true;
207 }
208 }
209 // Check if it's cell(row, col) format (two numeric arguments)
210 else if( args.Find( ',' ) != wxNOT_FOUND )
211 {
212 wxString rowStr = args.BeforeFirst( ',' ).Trim( true ).Trim( false );
213 wxString colStr = args.AfterFirst( ',' ).Trim( true ).Trim( false );
214
215 long rowNum, colNum;
216 if( !rowStr.ToLong( &rowNum ) || !colStr.ToLong( &colNum ) )
217 {
218 *token = wxString::Format( wxT( "<Unresolved: Invalid cell coordinates: %s>" ), args );
219 return true;
220 }
221
222 // Arguments are already 0-based
223 targetRow = rowNum;
224 targetCol = colNum;
225 }
226 else
227 {
228 *token = wxString::Format( wxT( "<Unresolved: Invalid CELL() syntax: %s>" ), args );
229 return true;
230 }
231
232 // Check bounds
233 if( targetRow < 0 || targetRow >= table->GetRowCount() || targetCol < 0
234 || targetCol >= table->GetColCount() )
235 {
236 wxString cellAddr;
237 if( targetRow >= 0 && targetCol >= 0 )
238 {
239 char colLetter = 'A' + ( targetCol % 26 );
240 cellAddr = wxString::Format( wxT( "%c%d" ), colLetter, targetRow );
241 }
242 else
243 {
244 cellAddr = args;
245 }
246 *token = wxString::Format( wxT( "<Unresolved: Cell %s not found>" ), cellAddr );
247 return true;
248 }
249
250 // Get the target cell and return its evaluated text
251 SCH_TABLECELL* targetCell = table->GetCell( targetRow, targetCol );
252 if( targetCell )
253 {
254 // Check for excessive recursion depth (circular references)
256 if( aDepth >= maxDepth )
257 {
258 *token = wxT( "<Circular reference>" );
259 return true;
260 }
261
262 *token = targetCell->GetShownText( aSettings, aPath, aAllowExtraText, aDepth + 1 );
263 return true;
264 }
265 else
266 {
267 *token = wxT( "<Unresolved: Cell not found>" );
268 return true;
269 }
270 }
271
272 // Fall back to sheet variables
273 if( sheet )
274 {
275 if( sheet->ResolveTextVar( aPath, token, depth + 1 ) )
276 return true;
277 }
278
279 return false;
280 };
281
282 wxString text = EDA_TEXT::GetShownText( aAllowExtraText, depth );
283
284 if( HasTextVars() )
285 text = ResolveTextVars( text, &tableCellResolver, depth );
286
287 VECTOR2I size = GetEnd() - GetStart();
288 int colWidth;
289
290 if( GetTextAngle().IsVertical() )
291 colWidth = abs( size.y ) - ( GetMarginTop() + GetMarginBottom() );
292 else
293 colWidth = abs( size.x ) - ( GetMarginLeft() + GetMarginRight() );
294
295 GetDrawFont( aSettings )
297
298 // Convert escape markers back to literal ${} and @{} for final display
299 // Only do this at the top level (aDepth == 0) to avoid premature unescaping in nested CELL() calls
300 if( aDepth == 0 )
301 {
302 text.Replace( wxT( "<<<ESC_DOLLAR:" ), wxT( "${" ) );
303 text.Replace( wxT( "<<<ESC_AT:" ), wxT( "@{" ) );
304 }
305
306 return text;
307}
308
309
311{
312 return static_cast<SCH_TABLE*>( GetParent() )->GetColWidth( GetColumn() );
313}
314
315
317{
318 SCH_TABLE* table = static_cast<SCH_TABLE*>( GetParent() );
319
320 table->SetColWidth( GetColumn(), aWidth );
321 table->Normalize();
322}
323
324
326{
327 return static_cast<SCH_TABLE*>( GetParent() )->GetRowHeight( GetRow() );
328}
329
330
332{
333 SCH_TABLE* table = static_cast<SCH_TABLE*>( GetParent() );
334
335 table->SetRowHeight( GetRow(), aHeight );
336 table->Normalize();
337}
338
339
340void SCH_TABLECELL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit,
341 int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
342{
343 const int cell_body_style = -1; // flag to disable box ouline plotting
344
345 if( m_colSpan >= 1 && m_rowSpan >= 1 )
346 SCH_TEXTBOX::Plot( aPlotter, aBackground, aPlotOpts, aUnit, cell_body_style, aOffset, aDimmed );
347}
348
349
350void SCH_TABLECELL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
351{
352 aList.emplace_back( _( "Table Cell" ), GetAddr() );
353
354 // Don't use GetShownText() here; we want to show the user the variable references
355 aList.emplace_back( _( "Text" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
356
357 aList.emplace_back( _( "Cell Width" ), aFrame->MessageTextFromValue( std::abs( GetEnd().x - GetStart().x ) ) );
358 aList.emplace_back( _( "Cell Height" ), aFrame->MessageTextFromValue( std::abs( GetEnd().y - GetStart().y ) ) );
359
360 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
361
362 wxString textStyle[] = { _( "Normal" ), _( "Italic" ), _( "Bold" ), _( "Bold Italic" ) };
363 int style = IsBold() && IsItalic() ? 3 : IsBold() ? 2 : IsItalic() ? 1 : 0;
364 aList.emplace_back( _( "Style" ), textStyle[style] );
365
366 aList.emplace_back( _( "Text Size" ), aFrame->MessageTextFromValue( GetTextWidth() ) );
367}
368
369
370double SCH_TABLECELL::Similarity( const SCH_ITEM& aOtherItem ) const
371{
372 if( aOtherItem.Type() != Type() )
373 return 0.0;
374
375 const SCH_TABLECELL& other = static_cast<const SCH_TABLECELL&>( aOtherItem );
376
377 double similarity = 1.0;
378
379 if( m_colSpan != other.m_colSpan )
380 similarity *= 0.9;
381
382 if( m_rowSpan != other.m_rowSpan )
383 similarity *= 0.9;
384
385 similarity *= SCH_TEXTBOX::Similarity( other );
386
387 return similarity;
388}
389
390
391bool SCH_TABLECELL::operator==( const SCH_ITEM& aOtherItem ) const
392{
393 if( aOtherItem.Type() != Type() )
394 return false;
395
396 const SCH_TABLECELL& other = static_cast<const SCH_TABLECELL&>( aOtherItem );
397
398 return *this == other;
399}
400
401
402bool SCH_TABLECELL::operator==( const SCH_TABLECELL& aOtherItem ) const
403{
404 return m_colSpan == aOtherItem.m_colSpan && m_rowSpan == aOtherItem.m_rowSpan
405 && SCH_TEXTBOX::operator==( aOtherItem );
406}
407
408
410{
412 {
415
424
425 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start X" ) );
426 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start Y" ) );
427 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "End X" ) );
428 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "End Y" ) );
429
430 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Shape" ) );
431 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Width" ) );
432 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Height" ) );
433 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Fill" ) );
434 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Fill Color" ) );
435 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Width" ) );
436 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Style" ) );
437 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Color" ) );
438 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Corner Radius" ) );
439
440 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
441 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
442 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Thickness" ) );
443 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
444 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Mirrored" ) );
445 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Visible" ) );
446 propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Hyperlink" ) );
447
448 const wxString tableProps = _( "Table" );
449
453 tableProps );
454
458 tableProps );
459
460 const wxString cellProps = _( "Cell Properties" );
461
463 _HKI( "Background Fill" ), &EDA_SHAPE::SetFilled, &EDA_SHAPE::IsSolidFill ),
464 cellProps );
465
466 propMgr.AddProperty( new PROPERTY<SCH_TABLECELL, COLOR4D, EDA_SHAPE>( _HKI( "Background Fill Color" ),
469 cellProps )
471 }
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:605
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:296
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:465
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.
std::vector< std::vector< std::string > > table
@ SCH_TABLECELL_T
Definition typeinfo.h:163
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683